platform_system_core/libunwindstack/DexFile.cpp
Yong Li 4ad538376a Fix memory leak of DexFile handle after release
The DexFile handle is allocated from heap in OpenFromFd/OpenFromMemory.
After releasing the unique_ptr, the DexFile handle itself is no longer
managed by the smart pointer. However, the DexFile handle is not freed
in the constructor of DexFileFromFile/DexFileFromMemory.

This change uses get() method to get the DexFile pointer while allowing
it to be managed by smart pointer so that it can be freed after method
end.

Added new unit tests to detect leaks.

Bug: 151966190

Test: Unwinding can still retrieve dex frame information during crash.
Test: Ran new unit tests before change and verified they fail, ran them
Test: after the change and verified they don't fail.

Signed-off-by: Yong Li <yongl0722@gmail.com>
Change-Id: I0627e1e255eb6644aba51e940c1a79ff78d568d7
(cherry picked from commit 489c3a8b35)
2020-03-23 13:47:00 -07:00

126 lines
3.7 KiB
C++

/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#define LOG_TAG "unwind"
#include <log/log.h>
#include <android-base/unique_fd.h>
#include <art_api/dex_file_support.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
#include "DexFile.h"
namespace unwindstack {
static bool CheckDexSupport() {
if (std::string err_msg; !art_api::dex::TryLoadLibdexfileExternal(&err_msg)) {
ALOGW("Failed to initialize DEX file support: %s", err_msg.c_str());
return false;
}
return true;
}
static bool HasDexSupport() {
static bool has_dex_support = CheckDexSupport();
return has_dex_support;
}
std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
MapInfo* info) {
if (!info->name.empty()) {
std::unique_ptr<DexFile> dex_file =
DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
if (dex_file) {
return dex_file;
}
}
return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
}
bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
uint64_t* method_offset) {
art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false);
if (method_info.offset == 0) {
return false;
}
*method_name = method_info.name;
*method_offset = dex_offset - method_info.offset;
return true;
}
std::unique_ptr<DexFileFromFile> DexFileFromFile::Create(uint64_t dex_file_offset_in_file,
const std::string& file) {
if (UNLIKELY(!HasDexSupport())) {
return nullptr;
}
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
return nullptr;
}
std::string error_msg;
std::unique_ptr<art_api::dex::DexFile> art_dex_file =
OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg);
if (art_dex_file == nullptr) {
return nullptr;
}
return std::unique_ptr<DexFileFromFile>(new DexFileFromFile(art_dex_file));
}
std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
Memory* memory,
const std::string& name) {
if (UNLIKELY(!HasDexSupport())) {
return nullptr;
}
std::vector<uint8_t> backing_memory;
for (size_t size = 0;;) {
std::string error_msg;
std::unique_ptr<art_api::dex::DexFile> art_dex_file =
OpenFromMemory(backing_memory.data(), &size, name, &error_msg);
if (art_dex_file != nullptr) {
return std::unique_ptr<DexFileFromMemory>(
new DexFileFromMemory(art_dex_file, std::move(backing_memory)));
}
if (!error_msg.empty()) {
return nullptr;
}
backing_memory.resize(size);
if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(),
backing_memory.size())) {
return nullptr;
}
}
}
} // namespace unwindstack