Merge "Mangle the pointers stored in PointerData." am: de9fe1e2de

Original change: https://android-review.googlesource.com/c/platform/bionic/+/2086791

Change-Id: I5ab322cba490aeb3238b711eefdeba1ac876ac24
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Christopher Ferris 2022-05-05 19:35:04 +00:00 committed by Automerger Merge Worker
commit 61125825f1
3 changed files with 48 additions and 33 deletions

View file

@ -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));
}
}

View file

@ -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);

View file

@ -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;
}