diff options
Diffstat (limited to 'lib/lsan/lsan_common_linux.cc')
-rw-r--r-- | lib/lsan/lsan_common_linux.cc | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index 10a434b5f851..ef8857fe8dbb 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -53,8 +53,7 @@ void InitializePlatformSpecificModules() { static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size, void *data) { - InternalVector<uptr> *frontier = - reinterpret_cast<InternalVector<uptr> *>(data); + Frontier *frontier = reinterpret_cast<Frontier *>(data); for (uptr j = 0; j < info->dlpi_phnum; j++) { const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]); // We're looking for .data and .bss sections, which reside in writeable, @@ -82,8 +81,8 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size, return 0; } -// Scan global variables for heap pointers. -void ProcessGlobalRegions(InternalVector<uptr> *frontier) { +// Scans global variables for heap pointers. +void ProcessGlobalRegions(Frontier *frontier) { // FIXME: dl_iterate_phdr acquires a linker lock, so we run a risk of // deadlocking by running this under StopTheWorld. However, the lock is // reentrant, so we should be able to fix this by acquiring the lock before @@ -91,32 +90,51 @@ void ProcessGlobalRegions(InternalVector<uptr> *frontier) { dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier); } -static uptr GetCallerPC(u32 stack_id) { +static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) { CHECK(stack_id); uptr size = 0; - const uptr *trace = StackDepotGet(stack_id, &size); + const uptr *trace = map->Get(stack_id, &size); // The top frame is our malloc/calloc/etc. The next frame is the caller. - CHECK_GE(size, 2); - return trace[1]; + if (size >= 2) + return trace[1]; + return 0; } -void ProcessPlatformSpecificAllocationsCb::operator()(void *p) const { - p = GetUserBegin(p); - LsanMetadata m(p); +struct ProcessPlatformAllocParam { + Frontier *frontier; + StackDepotReverseMap *stack_depot_reverse_map; +}; + +// ForEachChunk callback. Identifies unreachable chunks which must be treated as +// reachable. Marks them as reachable and adds them to the frontier. +static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) { + CHECK(arg); + ProcessPlatformAllocParam *param = + reinterpret_cast<ProcessPlatformAllocParam *>(arg); + chunk = GetUserBegin(chunk); + LsanMetadata m(chunk); if (m.allocated() && m.tag() != kReachable) { - if (linker->containsAddress(GetCallerPC(m.stack_trace_id()))) { + u32 stack_id = m.stack_trace_id(); + uptr caller_pc = 0; + if (stack_id > 0) + caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map); + // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark + // it as reachable, as we can't properly report its allocation stack anyway. + if (caller_pc == 0 || linker->containsAddress(caller_pc)) { m.set_tag(kReachable); - frontier_->push_back(reinterpret_cast<uptr>(p)); + param->frontier->push_back(chunk); } } } -// Handle dynamically allocated TLS blocks by treating all chunks allocated from -// ld-linux.so as reachable. -void ProcessPlatformSpecificAllocations(InternalVector<uptr> *frontier) { +// Handles dynamically allocated TLS blocks by treating all chunks allocated +// from ld-linux.so as reachable. +void ProcessPlatformSpecificAllocations(Frontier *frontier) { if (!flags()->use_tls) return; if (!linker) return; - ForEachChunk(ProcessPlatformSpecificAllocationsCb(frontier)); + StackDepotReverseMap stack_depot_reverse_map; + ProcessPlatformAllocParam arg = {frontier, &stack_depot_reverse_map}; + ForEachChunk(ProcessPlatformSpecificAllocationsCb, &arg); } } // namespace __lsan |