diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp index b982c0ae8..eaa0eb7c7 100644 --- a/libc/malloc_debug/PointerData.cpp +++ b/libc/malloc_debug/PointerData.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -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(ptr); size_t hash_index = 0; if (backtrace_enabled_) { hash_index = AddBacktrace(g_debug->config().backtrace_frames()); } std::lock_guard pointer_guard(pointer_mutex_); - pointers_[pointer] = PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index}; + uintptr_t mangled_ptr = ManglePointer(reinterpret_cast(ptr)); + pointers_[mangled_ptr] = + PointerInfoType{PointerInfoType::GetEncodedSize(pointer_size), hash_index}; } void PointerData::Remove(const void* ptr) { - uintptr_t pointer = reinterpret_cast(ptr); size_t hash_index; { std::lock_guard pointer_guard(pointer_mutex_); - auto entry = pointers_.find(pointer); + uintptr_t mangled_ptr = ManglePointer(reinterpret_cast(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(ptr); size_t hash_index; { std::lock_guard pointer_guard(pointer_mutex_); - auto entry = pointers_.find(pointer); + uintptr_t mangled_ptr = ManglePointer(reinterpret_cast(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(info.pointer); + uintptr_t pointer = DemanglePointer(info.mangled_ptr); + uint8_t* memory = reinterpret_cast(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(info.pointer)); + Header* header = g_debug->GetHeader(reinterpret_cast(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(info.pointer)); + usable_size = g_dispatch->malloc_usable_size(reinterpret_cast(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(info.pointer); + const uint8_t* memory = reinterpret_cast(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(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(info.pointer); + last = reinterpret_cast(DemanglePointer(info.mangled_ptr)); } - free_pointers_.emplace_back(FreePointerInfoType{pointer, hash_index}); + uintptr_t mangled_ptr = ManglePointer(reinterpret_cast(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(ptr); std::lock_guard 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* list, bool only_with_backtr for (const auto& entry : pointers_) { FrameInfoType* frame_info = nullptr; std::vector* 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* 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* 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* 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(ptr); std::lock_guard pointer_guard(pointer_mutex_); - return pointers_.count(pointer) != 0; + uintptr_t mangled_ptr = ManglePointer(reinterpret_cast(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 fn) { + std::lock_guard pointer_guard(pointer_mutex_); + for (const auto entry : pointers_) { + fn(DemanglePointer(entry.first)); + } +} diff --git a/libc/malloc_debug/PointerData.h b/libc/malloc_debug/PointerData.h index 92d2653d6..97eec0aee 100644 --- a/libc/malloc_debug/PointerData.h +++ b/libc/malloc_debug/PointerData.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -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 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::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); diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index 9f38946af..d608f5d02 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -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(it->first)), arg); - } + PointerData::IteratePointers([&callback, &arg](uintptr_t pointer) { + callback(pointer, InternalMallocUsableSize(reinterpret_cast(pointer)), arg); + }); return 0; }