Merge "Mangle the pointers stored in PointerData." am: de9fe1e2de
am: 61125825f1
Original change: https://android-review.googlesource.com/c/platform/bionic/+/2086791 Change-Id: Ia5a906f38928eaf7507ea1e4f374f90afff75c85 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
cd7937c198
3 changed files with 48 additions and 33 deletions
|
@ -35,6 +35,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
@ -195,40 +196,41 @@ void PointerData::RemoveBacktrace(size_t hash_index) {
|
|||
}
|
||||
|
||||
void PointerData::Add(const void* ptr, size_t pointer_size) {
|
||||
uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
|
||||
size_t hash_index = 0;
|
||||
if (backtrace_enabled_) {
|
||||
hash_index = AddBacktrace(g_debug->config().backtrace_frames());
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
pointers_[pointer] = PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
|
||||
uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
|
||||
pointers_[mangled_ptr] =
|
||||
PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index};
|
||||
}
|
||||
|
||||
void PointerData::Remove(const void* ptr) {
|
||||
uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
|
||||
size_t hash_index;
|
||||
{
|
||||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
auto entry = pointers_.find(pointer);
|
||||
uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
|
||||
auto entry = pointers_.find(mangled_ptr);
|
||||
if (entry == pointers_.end()) {
|
||||
// Attempt to remove unknown pointer.
|
||||
error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
|
||||
error_log("No tracked pointer found for 0x%" PRIxPTR, DemanglePointer(mangled_ptr));
|
||||
return;
|
||||
}
|
||||
hash_index = entry->second.hash_index;
|
||||
pointers_.erase(pointer);
|
||||
pointers_.erase(mangled_ptr);
|
||||
}
|
||||
|
||||
RemoveBacktrace(hash_index);
|
||||
}
|
||||
|
||||
size_t PointerData::GetFrames(const void* ptr, uintptr_t* frames, size_t max_frames) {
|
||||
uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
|
||||
size_t hash_index;
|
||||
{
|
||||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
auto entry = pointers_.find(pointer);
|
||||
uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
|
||||
auto entry = pointers_.find(mangled_ptr);
|
||||
if (entry == pointers_.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -274,7 +276,8 @@ void PointerData::LogBacktrace(size_t hash_index) {
|
|||
|
||||
void PointerData::LogFreeError(const FreePointerInfoType& info, size_t max_cmp_bytes) {
|
||||
error_log(LOG_DIVIDER);
|
||||
uint8_t* memory = reinterpret_cast<uint8_t*>(info.pointer);
|
||||
uintptr_t pointer = DemanglePointer(info.mangled_ptr);
|
||||
uint8_t* memory = reinterpret_cast<uint8_t*>(pointer);
|
||||
error_log("+++ ALLOCATION %p USED AFTER FREE", memory);
|
||||
uint8_t fill_free_value = g_debug->config().fill_free_value();
|
||||
for (size_t i = 0; i < max_cmp_bytes; i++) {
|
||||
|
@ -296,13 +299,14 @@ void PointerData::LogFreeError(const FreePointerInfoType& info, size_t max_cmp_b
|
|||
|
||||
void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
|
||||
size_t usable_size;
|
||||
uintptr_t pointer = DemanglePointer(info.mangled_ptr);
|
||||
if (g_debug->HeaderEnabled()) {
|
||||
// Check to see if the tag data has been damaged.
|
||||
Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(info.pointer));
|
||||
Header* header = g_debug->GetHeader(reinterpret_cast<const void*>(pointer));
|
||||
if (header->tag != DEBUG_FREE_TAG) {
|
||||
error_log(LOG_DIVIDER);
|
||||
error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE",
|
||||
info.pointer, header->tag);
|
||||
error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE", pointer,
|
||||
header->tag);
|
||||
error_log(LOG_DIVIDER);
|
||||
if (g_debug->config().options() & ABORT_ON_ERROR) {
|
||||
abort();
|
||||
|
@ -314,14 +318,14 @@ void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
|
|||
}
|
||||
usable_size = header->usable_size;
|
||||
} else {
|
||||
usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(info.pointer));
|
||||
usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<const void*>(pointer));
|
||||
}
|
||||
|
||||
size_t bytes = (usable_size < g_debug->config().fill_on_free_bytes())
|
||||
? usable_size
|
||||
: g_debug->config().fill_on_free_bytes();
|
||||
size_t max_cmp_bytes = bytes;
|
||||
const uint8_t* memory = reinterpret_cast<const uint8_t*>(info.pointer);
|
||||
const uint8_t* memory = reinterpret_cast<const uint8_t*>(pointer);
|
||||
while (bytes > 0) {
|
||||
size_t bytes_to_cmp = (bytes < g_cmp_mem.size()) ? bytes : g_cmp_mem.size();
|
||||
if (memcmp(memory, g_cmp_mem.data(), bytes_to_cmp) != 0) {
|
||||
|
@ -333,8 +337,6 @@ void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
|
|||
}
|
||||
|
||||
void* PointerData::AddFreed(const void* ptr) {
|
||||
uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
size_t hash_index = 0;
|
||||
size_t num_frames = g_debug->config().free_track_backtrace_num_frames();
|
||||
if (num_frames) {
|
||||
|
@ -348,10 +350,11 @@ void* PointerData::AddFreed(const void* ptr) {
|
|||
free_pointers_.pop_front();
|
||||
VerifyFreedPointer(info);
|
||||
RemoveBacktrace(info.hash_index);
|
||||
last = reinterpret_cast<void*>(info.pointer);
|
||||
last = reinterpret_cast<void*>(DemanglePointer(info.mangled_ptr));
|
||||
}
|
||||
|
||||
free_pointers_.emplace_back(FreePointerInfoType{pointer, hash_index});
|
||||
uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
|
||||
free_pointers_.emplace_back(FreePointerInfoType{mangled_ptr, hash_index});
|
||||
return last;
|
||||
}
|
||||
|
||||
|
@ -361,7 +364,7 @@ void PointerData::LogFreeBacktrace(const void* ptr) {
|
|||
uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
|
||||
std::lock_guard<std::mutex> freed_guard(free_pointer_mutex_);
|
||||
for (const auto& info : free_pointers_) {
|
||||
if (info.pointer == pointer) {
|
||||
if (DemanglePointer(info.mangled_ptr) == pointer) {
|
||||
hash_index = info.hash_index;
|
||||
break;
|
||||
}
|
||||
|
@ -388,6 +391,7 @@ void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtr
|
|||
for (const auto& entry : pointers_) {
|
||||
FrameInfoType* frame_info = nullptr;
|
||||
std::vector<unwindstack::FrameData>* backtrace_info = nullptr;
|
||||
uintptr_t pointer = DemanglePointer(entry.first);
|
||||
size_t hash_index = entry.second.hash_index;
|
||||
if (hash_index > kBacktraceEmptyIndex) {
|
||||
auto frame_entry = frames_.find(hash_index);
|
||||
|
@ -397,7 +401,7 @@ void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtr
|
|||
// occurs after the hash_index and frame data have been added.
|
||||
// When removing a pointer, the pointer is deleted before the frame
|
||||
// data.
|
||||
error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
|
||||
error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
|
||||
} else {
|
||||
frame_info = &frame_entry->second;
|
||||
}
|
||||
|
@ -405,7 +409,7 @@ void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtr
|
|||
if (g_debug->config().options() & BACKTRACE_FULL) {
|
||||
auto backtrace_entry = backtraces_info_.find(hash_index);
|
||||
if (backtrace_entry == backtraces_info_.end()) {
|
||||
error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", entry.first, hash_index);
|
||||
error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
|
||||
} else {
|
||||
backtrace_info = &backtrace_entry->second;
|
||||
}
|
||||
|
@ -415,7 +419,7 @@ void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtr
|
|||
continue;
|
||||
}
|
||||
|
||||
list->emplace_back(ListInfoType{entry.first, 1, entry.second.RealSize(),
|
||||
list->emplace_back(ListInfoType{pointer, 1, entry.second.RealSize(),
|
||||
entry.second.ZygoteChildAlloc(), frame_info, backtrace_info});
|
||||
}
|
||||
|
||||
|
@ -550,9 +554,9 @@ void PointerData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_siz
|
|||
}
|
||||
|
||||
bool PointerData::Exists(const void* ptr) {
|
||||
uintptr_t pointer = reinterpret_cast<uintptr_t>(ptr);
|
||||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
return pointers_.count(pointer) != 0;
|
||||
uintptr_t mangled_ptr = ManglePointer(reinterpret_cast<uintptr_t>(ptr));
|
||||
return pointers_.count(mangled_ptr) != 0;
|
||||
}
|
||||
|
||||
void PointerData::DumpLiveToFile(int fd) {
|
||||
|
@ -637,3 +641,10 @@ void PointerData::PostForkChild() __attribute__((no_thread_safety_analysis)) {
|
|||
free_pointer_mutex_.try_lock();
|
||||
free_pointer_mutex_.unlock();
|
||||
}
|
||||
|
||||
void PointerData::IteratePointers(std::function<void(uintptr_t pointer)> fn) {
|
||||
std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
|
||||
for (const auto entry : pointers_) {
|
||||
fn(DemanglePointer(entry.first));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
@ -99,7 +100,7 @@ struct PointerInfoType {
|
|||
};
|
||||
|
||||
struct FreePointerInfoType {
|
||||
uintptr_t pointer;
|
||||
uintptr_t mangled_ptr;
|
||||
size_t hash_index;
|
||||
};
|
||||
|
||||
|
@ -134,16 +135,14 @@ class PointerData : public OptionData {
|
|||
void PostForkParent();
|
||||
void PostForkChild();
|
||||
|
||||
static void IteratePointers(std::function<void(uintptr_t pointer)> fn);
|
||||
|
||||
static size_t AddBacktrace(size_t num_frames);
|
||||
static void RemoveBacktrace(size_t hash_index);
|
||||
|
||||
static void Add(const void* pointer, size_t size);
|
||||
static void Remove(const void* pointer);
|
||||
|
||||
typedef std::unordered_map<uintptr_t, PointerInfoType>::iterator iterator;
|
||||
static iterator begin() { return pointers_.begin(); }
|
||||
static iterator end() { return pointers_.end(); }
|
||||
|
||||
static void* AddFreed(const void* pointer);
|
||||
static void LogFreeError(const FreePointerInfoType& info, size_t usable_size);
|
||||
static void LogFreeBacktrace(const void* ptr);
|
||||
|
@ -162,6 +161,12 @@ class PointerData : public OptionData {
|
|||
static bool Exists(const void* pointer);
|
||||
|
||||
private:
|
||||
// Only keep mangled pointers in internal data structures. This avoids
|
||||
// problems where libmemunreachable finds these pointers and thinks they
|
||||
// are not unreachable.
|
||||
static inline uintptr_t ManglePointer(uintptr_t pointer) { return pointer ^ UINTPTR_MAX; }
|
||||
static inline uintptr_t DemanglePointer(uintptr_t pointer) { return pointer ^ UINTPTR_MAX; }
|
||||
|
||||
static std::string GetHashString(uintptr_t* frames, size_t num_frames);
|
||||
static void LogBacktrace(size_t hash_index);
|
||||
|
||||
|
|
|
@ -890,10 +890,9 @@ int debug_malloc_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t
|
|||
void* arg) {
|
||||
ScopedConcurrentLock lock;
|
||||
if (g_debug->TrackPointers()) {
|
||||
// Since malloc is disabled, don't bother acquiring any locks.
|
||||
for (auto it = PointerData::begin(); it != PointerData::end(); ++it) {
|
||||
callback(it->first, InternalMallocUsableSize(reinterpret_cast<void*>(it->first)), arg);
|
||||
}
|
||||
PointerData::IteratePointers([&callback, &arg](uintptr_t pointer) {
|
||||
callback(pointer, InternalMallocUsableSize(reinterpret_cast<void*>(pointer)), arg);
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue