From ddc5ce1800960dea19253a16a64b4793ec99d8f9 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 13 Nov 2020 10:58:31 +0100 Subject: [PATCH] UserspaceEmulator: When auditing accesses, show nearest mallocation Instead of always showing the preceding mallocation, prefer showing the following one *if* it's closer to the audited address. This makes it easier to find bugs where the access is just before an allocation instead of just after it. --- DevTools/UserspaceEmulator/MallocTracer.cpp | 44 +++++++++++++++++---- DevTools/UserspaceEmulator/MallocTracer.h | 1 + 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/DevTools/UserspaceEmulator/MallocTracer.cpp b/DevTools/UserspaceEmulator/MallocTracer.cpp index 6f88d9a446..5746d765a2 100644 --- a/DevTools/UserspaceEmulator/MallocTracer.cpp +++ b/DevTools/UserspaceEmulator/MallocTracer.cpp @@ -136,6 +136,18 @@ MallocTracer::Mallocation* MallocTracer::find_mallocation_before(FlatPtr address return found_mallocation; } +MallocTracer::Mallocation* MallocTracer::find_mallocation_after(FlatPtr address) +{ + Mallocation* found_mallocation = nullptr; + for (auto& mallocation : m_mallocations) { + if (mallocation.address <= address) + continue; + if (!found_mallocation || (mallocation.address < found_mallocation->address)) + found_mallocation = &mallocation; + } + return found_mallocation; +} + void MallocTracer::audit_read(FlatPtr address, size_t size) { if (!m_auditing_enabled) @@ -149,10 +161,18 @@ void MallocTracer::audit_read(FlatPtr address, size_t size) if (!mallocation) { reportln("\n=={}== \033[31;1mHeap buffer overflow\033[0m, invalid {}-byte read at address {:p}", getpid(), size, address); Emulator::the().dump_backtrace(); - if ((mallocation = find_mallocation_before(address))) { - size_t offset_into_mallocation = address - mallocation->address; - reportln("=={}== Address is {} byte(s) after block of size {}, allocated at:", getpid(), offset_into_mallocation - mallocation->size, mallocation->size); - Emulator::the().dump_backtrace(mallocation->malloc_backtrace); + auto* mallocation_before = find_mallocation_before(address); + auto* mallocation_after = find_mallocation_after(address); + size_t distance_to_mallocation_before = mallocation_before ? (address - mallocation_before->address - mallocation_before->size) : 0; + size_t distance_to_mallocation_after = mallocation_after ? (mallocation_after->address - address) : 0; + if (mallocation_before && (!mallocation_after || distance_to_mallocation_before < distance_to_mallocation_after)) { + reportln("=={}== Address is {} byte(s) after block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_before, mallocation_before->size, mallocation_before->address); + Emulator::the().dump_backtrace(mallocation_before->malloc_backtrace); + return; + } + if (mallocation_after && (!mallocation_before || distance_to_mallocation_after < distance_to_mallocation_before)) { + reportln("=={}== Address is {} byte(s) before block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_after, mallocation_after->size, mallocation_after->address); + Emulator::the().dump_backtrace(mallocation_after->malloc_backtrace); } return; } @@ -182,10 +202,18 @@ void MallocTracer::audit_write(FlatPtr address, size_t size) if (!mallocation) { reportln("\n=={}== \033[31;1mHeap buffer overflow\033[0m, invalid {}-byte write at address {:p}", getpid(), size, address); Emulator::the().dump_backtrace(); - if ((mallocation = find_mallocation_before(address))) { - size_t offset_into_mallocation = address - mallocation->address; - reportln("=={}== Address is {} byte(s) into block of size {}, allocated at:", getpid(), offset_into_mallocation, mallocation->size); - Emulator::the().dump_backtrace(mallocation->malloc_backtrace); + auto* mallocation_before = find_mallocation_before(address); + auto* mallocation_after = find_mallocation_after(address); + size_t distance_to_mallocation_before = mallocation_before ? (address - mallocation_before->address - mallocation_before->size) : 0; + size_t distance_to_mallocation_after = mallocation_after ? (mallocation_after->address - address) : 0; + if (mallocation_before && (!mallocation_after || distance_to_mallocation_before < distance_to_mallocation_after)) { + reportln("=={}== Address is {} byte(s) after block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_before, mallocation_before->size, mallocation_before->address); + Emulator::the().dump_backtrace(mallocation_before->malloc_backtrace); + return; + } + if (mallocation_after && (!mallocation_before || distance_to_mallocation_after < distance_to_mallocation_before)) { + reportln("=={}== Address is {} byte(s) before block of size {}, identity {:p}, allocated at:", getpid(), distance_to_mallocation_after, mallocation_after->size, mallocation_after->address); + Emulator::the().dump_backtrace(mallocation_after->malloc_backtrace); } return; } diff --git a/DevTools/UserspaceEmulator/MallocTracer.h b/DevTools/UserspaceEmulator/MallocTracer.h index fb7f99a307..e122c1069e 100644 --- a/DevTools/UserspaceEmulator/MallocTracer.h +++ b/DevTools/UserspaceEmulator/MallocTracer.h @@ -64,6 +64,7 @@ private: Mallocation* find_mallocation(FlatPtr); Mallocation* find_mallocation_before(FlatPtr); + Mallocation* find_mallocation_after(FlatPtr); bool is_reachable(const Mallocation&) const; Vector m_mallocations;