From 3d5841471b1ea654cbe76b8948e8689e66cc1a8e Mon Sep 17 00:00:00 2001 From: meteors117 Date: Thu, 19 Jun 2025 16:13:08 +0800 Subject: [PATCH 1/5] [Huawei][HWASAN] Default parameter optimization. Set the default size of Quarantine and ringbuffer on main thread and other threads. Signed-off-by: meteors117 --- compiler-rt/lib/hwasan/hwasan_allocator.h | 3 +- compiler-rt/lib/hwasan/hwasan_flags.inc | 9 +++++- compiler-rt/lib/hwasan/hwasan_quarantine.cpp | 9 +++--- compiler-rt/lib/hwasan/hwasan_quarantine.h | 7 ++++- compiler-rt/lib/hwasan/hwasan_report.cpp | 3 +- compiler-rt/lib/hwasan/hwasan_thread.cpp | 33 ++++++++++++++++---- compiler-rt/lib/hwasan/hwasan_thread.h | 3 ++ compiler-rt/lib/hwasan/hwasan_thread_list.h | 25 ++++++++++++--- 8 files changed, 71 insertions(+), 21 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h index 7514e2735a6c..dfac62f09cbc 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.h +++ b/compiler-rt/lib/hwasan/hwasan_allocator.h @@ -134,7 +134,8 @@ inline bool InTaggableRegion(uptr addr) { __attribute__((always_inline)) static bool ShouldPrintQuarantineDwillTime() { return flags()->heap_quarantine_max > 0 && flags()->enable_heap_quarantine_debug && - flags()->heap_quarantine_thread_max_count > 0; + (flags()->heap_quarantine_thread_max_count > 0 || + flags()->heap_quarantine_main_thread_max_count > 0); } // OHOS_LOCAL end diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc index e4719b2b6de1..b76a4993086c 100644 --- a/compiler-rt/lib/hwasan/hwasan_flags.inc +++ b/compiler-rt/lib/hwasan/hwasan_flags.inc @@ -56,10 +56,15 @@ HWASAN_FLAG(int, heap_history_size, 1023, "to find bugs.") // OHOS_LOCAL begin HWASAN_FLAG( - int, heap_history_size_main_thread, 102300, + int, heap_history_size_main_thread, 1023000, "The number of heap (de)allocations remembered for the main thread. " "Affects the quality of heap-related reports, but not the ability " "to find bugs.") +HWASAN_FLAG(int, heap_history_size_main_thread_native, 102300, + "The number of heap (de)allocations remembered for the main thread " + "of native process. " + "Affects the quality of heap-related reports, but not the ability " + "to find bugs.") // OHOS_LOCAL end HWASAN_FLAG(bool, export_memory_stats, true, "Export up-to-date memory stats through /proc") @@ -118,6 +123,8 @@ HWASAN_FLAG(int, memory_around_register_size, 128, // Set the quarantine area for freed heap, which is used to detect UAF-Write and // Overflow-Write. Provide the detection capability for dynamic libraries // compiled without hwasan option. +HWASAN_FLAG(int, heap_quarantine_main_thread_max_count, 1024, + "Set the maximum count for heap quarantine main thread.") HWASAN_FLAG(int, heap_quarantine_thread_max_count, 128, "Set the maximum count for heap quarantine per thread.") HWASAN_FLAG(int, heap_quarantine_min, 0, diff --git a/compiler-rt/lib/hwasan/hwasan_quarantine.cpp b/compiler-rt/lib/hwasan/hwasan_quarantine.cpp index 4ca56b030f1d..6ffbe4980b3a 100644 --- a/compiler-rt/lib/hwasan/hwasan_quarantine.cpp +++ b/compiler-rt/lib/hwasan/hwasan_quarantine.cpp @@ -26,7 +26,7 @@ void HeapQuarantineController::ClearHeapQuarantine(AllocatorCache *cache) { if (heap_quarantine_list_) { DeallocateWithHeapQuarantcheck(heap_quarantine_tail_, cache); size_t sz = RoundUpTo( - flags()->heap_quarantine_thread_max_count * sizeof(HeapQuarantine), + heap_quarantine_size_ * sizeof(HeapQuarantine), GetPageSizeCached()); UnmapOrDie(heap_quarantine_list_, sz); heap_quarantine_tail_ = 0; @@ -41,11 +41,11 @@ bool HeapQuarantineController::TryPutInQuarantineWithDealloc( return false; if ((flags()->heap_quarantine_max > 0) && (flags()->heap_quarantine_max > s && flags()->heap_quarantine_min <= s)) { - if (UNLIKELY(flags()->heap_quarantine_thread_max_count <= 0)) + if (UNLIKELY(heap_quarantine_size_ <= 0)) return false; if (UNLIKELY(heap_quarantine_list_ == nullptr)) { size_t sz = RoundUpTo( - flags()->heap_quarantine_thread_max_count * sizeof(HeapQuarantine), + heap_quarantine_size_ * sizeof(HeapQuarantine), GetPageSizeCached()); heap_quarantine_list_ = reinterpret_cast( MmapOrDie(sz, "HeapQuarantine", 0)); @@ -68,8 +68,7 @@ void HeapQuarantineController::PutInQuarantineWithDealloc( heap_quarantine_tail_ * (current_time_point - pre_time_point); pre_time_point = current_time_point; } - if (UNLIKELY(heap_quarantine_tail_ >= - flags()->heap_quarantine_thread_max_count)) { + if (UNLIKELY(heap_quarantine_tail_ >= heap_quarantine_size_)) { // free 1/3 heap_quarantine_list u32 free_count = heap_quarantine_tail_ / 3; free_count = free_count > 0 ? free_count : 1; diff --git a/compiler-rt/lib/hwasan/hwasan_quarantine.h b/compiler-rt/lib/hwasan/hwasan_quarantine.h index 6cf3b077c7f9..bc7416df9b2e 100644 --- a/compiler-rt/lib/hwasan/hwasan_quarantine.h +++ b/compiler-rt/lib/hwasan/hwasan_quarantine.h @@ -27,6 +27,7 @@ struct HeapQuarantine { class HeapQuarantineController { private: u32 heap_quarantine_tail_; + u32 heap_quarantine_size_; HeapQuarantine *heap_quarantine_list_; size_t count{0}; size_t persist_interval{0}; @@ -36,9 +37,13 @@ class HeapQuarantineController { void DeallocateWithHeapQuarantcheck(u32 free_count, AllocatorCache *cache); public: - void Init() { + void Init(int tid) { heap_quarantine_tail_ = 0; heap_quarantine_list_ = nullptr; + if (tid == internal_getpid()) + heap_quarantine_size_ = flags()->heap_quarantine_main_thread_max_count; + else + heap_quarantine_size_ = flags()->heap_quarantine_thread_max_count; } void ClearHeapQuarantine(AllocatorCache *cache); diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index 1bbe681c6590..a0827639fee4 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -444,8 +444,7 @@ void PrintAddressDescription( GetStackTraceFromId(har.alloc_context_id).Print(); Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ring_index + 1, - t->IsMainThread() ? flags()->heap_history_size_main_thread - : flags()->heap_history_size); + t->HeapHistorySize()); t->Announce(); num_descriptions_printed++; }; diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index b6d2a49bf9da..7f0e0524fc73 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -35,6 +35,20 @@ void Thread::InitRandomState() { stack_allocations_->push(0); } +#define PATH_NAME_MAX_SIZE 40 +#define PROC_NAME_MAX_SIZE 256 +static bool IsNativeProcess(uptr ppid) { + if (ppid == 0) + return true; + char proc_path[PATH_NAME_MAX_SIZE] = {0}; + internal_snprintf(proc_path, sizeof(proc_path), "/proc/%d/cmdline", ppid); + fd_t f = OpenFile(proc_path, RdOnly); + char proc_name[PROC_NAME_MAX_SIZE + 1] = {0}; + const char *target_name = "appspawn"; + ReadFromFile(f, proc_name, PROC_NAME_MAX_SIZE); + return internal_strncmp(proc_name, target_name, sizeof(target_name)) != 0; +} + void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, const InitState *state) { CHECK_EQ(0, unique_id_); // try to catch bad stack reuse @@ -45,8 +59,17 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, unique_id_ = atomic_fetch_add(&unique_id, 1, memory_order_relaxed); // OHOS_LOCAL begin - if (auto sz = IsMainThread() ? flags()->heap_history_size_main_thread - : flags()->heap_history_size) + if (IsMainThread()) { + uptr ppid = internal_getppid(); + if (!IsNativeProcess(ppid)) { + heap_history_size_ = flags()->heap_history_size_main_thread; + } else { + heap_history_size_ = flags()->heap_history_size_main_thread_native; + } + } else { + heap_history_size_ = flags()->heap_history_size; + } + if (auto sz = HeapHistorySize()) // OHOS_LOCAL end heap_allocations_ = HeapAllocationsRingBuffer::New(sz); trace_heap_allocation_ = true; // OHOS_LOCAL @@ -58,7 +81,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, #endif InitStackAndTls(state); tid_ = GetTid(); // OHOS_LOCAL - heap_quarantine_controller()->Init(); // OHOS_LOCAL + heap_quarantine_controller()->Init(tid_); // OHOS_LOCAL } void Thread::InitStackRingBuffer(uptr stack_buffer_start, @@ -137,9 +160,7 @@ void Thread::Print(const char *Prefix) { Prefix, unique_id_, (void *)this, stack_bottom(), stack_top(), stack_top() - stack_bottom(), tls_begin(), tls_end(), heap_allocations() ? heap_allocations()->realsize() : 0, - IsMainThread() ? flags()->heap_history_size_main_thread - : flags()->heap_history_size, - all_record_count_, all_record_count_overflow_, tid_); + HeapHistorySize(), all_record_count_, all_record_count_overflow_, tid_); // OHOS_LOCAL end } diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h index b066d9fb6e8d..5ab083cbde53 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.h +++ b/compiler-rt/lib/hwasan/hwasan_thread.h @@ -50,6 +50,8 @@ class Thread { bool IsMainThread() { return unique_id_ == 0; } // OHOS_LOCAL begin + int HeapHistorySize() { return heap_history_size_; } + void inc_record(void) { all_record_count_++; if (all_record_count_ == 0) { @@ -133,6 +135,7 @@ class Thread { u64 all_record_count_ = 0; // Count record u64 all_record_count_overflow_ = 0; // Whether all_record_count_ overflow. + int heap_history_size_ = 0; // OHOS_LOCAL end friend struct ThreadListHead; diff --git a/compiler-rt/lib/hwasan/hwasan_thread_list.h b/compiler-rt/lib/hwasan/hwasan_thread_list.h index 3c297525a677..f09789136122 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread_list.h +++ b/compiler-rt/lib/hwasan/hwasan_thread_list.h @@ -49,6 +49,7 @@ #include "hwasan_thread.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_placement_new.h" namespace __hwasan { @@ -67,6 +68,20 @@ static uptr RingBufferSize() { return 0; } +#define PATH_NAME_MAX_SIZE 40 +#define PROC_NAME_MAX_SIZE 256 +static bool IsNativeProcess(uptr ppid) { + if (ppid == 0) + return true; + char proc_path[PATH_NAME_MAX_SIZE] = {0}; + internal_snprintf(proc_path, sizeof(proc_path), "/proc/%d/cmdline", ppid); + fd_t f = OpenFile(proc_path, RdOnly); + char proc_name[PROC_NAME_MAX_SIZE + 1] = {0}; + const char *target_name = "appspawn"; + ReadFromFile(f, proc_name, PROC_NAME_MAX_SIZE); + return internal_strncmp(proc_name, target_name, sizeof(target_name)) != 0; +} + struct ThreadStats { uptr n_live_threads; uptr total_stack_size; @@ -85,8 +100,10 @@ class HwasanThreadList { thread_alloc_size_ = RoundUpTo(ring_buffer_size_ + sizeof(Thread), ring_buffer_size_ * 2); // OHOS_LOCAL begin - freed_rb_fallback_ = - HeapAllocationsRingBuffer::New(flags()->heap_history_size_main_thread); + uptr ppid = internal_getppid(); + freed_rb_fallback_ = HeapAllocationsRingBuffer::New( + IsNativeProcess(ppid) ? flags()->heap_history_size_main_thread_native + : flags()->heap_history_size_main_thread); freed_rb_list_ = nullptr; freed_rb_list_size_ = 0; @@ -177,9 +194,7 @@ class HwasanThreadList { freed_rb_list_size_ = left; } HeapAllocationsRingBuffer *freed_allocations_; - freed_allocations_ = HeapAllocationsRingBuffer::New( - t->IsMainThread() ? flags()->heap_history_size_main_thread - : flags()->heap_history_size); + freed_allocations_ = HeapAllocationsRingBuffer::New(t->HeapHistorySize()); HeapAllocationsRingBuffer *rb = t->heap_allocations(); for (uptr i = 0, size = rb->realsize(); i < size; i++) { -- Gitee From 7dcbb7b69ab6257e65be6f721357b1a51ef6aa60 Mon Sep 17 00:00:00 2001 From: meteors117 Date: Thu, 19 Jun 2025 16:14:39 +0800 Subject: [PATCH 2/5] [Huawei][HWASAN] Add test case. Add a test case to check the Quarantine size on different threads. Signed-off-by: meteors117 --- .../hwasan/TestCases/heap_quarantine_size.cpp | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 compiler-rt/test/hwasan/TestCases/heap_quarantine_size.cpp diff --git a/compiler-rt/test/hwasan/TestCases/heap_quarantine_size.cpp b/compiler-rt/test/hwasan/TestCases/heap_quarantine_size.cpp new file mode 100644 index 000000000000..04d830bab031 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/heap_quarantine_size.cpp @@ -0,0 +1,76 @@ +// Check the heap_quarantine size correctly. +// RUN: %clangxx_hwasan %s -o %t +// RUN: %env_hwasan_opts=heap_quarantine_max=1025 %run %t 2>&1 |\ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-1024 +// RUN: %env_hwasan_opts=heap_quarantine_max=1025:heap_quarantine_main_thread_max_count=2048 %run %t 2>&1 |\ +// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-2048 + +#include +#include +#include +#include +#include +#include + +std::atomic l{0}; +std::atomic s{0}; +static const int kSize = 1 << 4; + +// call free to create HeapQuarantine. +void malloc_and_free() { + char *x = (char *)malloc(kSize); + free(x); + l++; + printf("l = %d.\n", l.load()); + while (s == 0) { + } +} + +int main(int argc, char **argv) { + char *y = (char *)malloc(kSize); + free(y); + l++; + printf("l = %d.\n", l.load()); + + std::thread t(malloc_and_free); + + // busy wait until l reaches 2 + // to make sure the quarantine is created. + while (l < 2) { + } + + unsigned long long quarantine_sz_main = 0; + unsigned long long quarantine_sz = 0; + unsigned long long sz = 0; + std::ifstream mapsFile("/proc/self/maps"); + std::string line = ""; + int base = 16; + while (getline(mapsFile, line)) { + if (line.find(":HeapQuarantine") != std::string::npos) { + std::istringstream iss(line); + std::string addrs; + iss >> addrs; + std::string start = addrs.substr(0, addrs.find('-')); + std::string end = addrs.substr(addrs.find('-') + 1); + sz = std::stoull(end, nullptr, base) - std::stoull(start, nullptr, base); + if (sz > 0x1000) { + quarantine_sz_main = sz; + } else { + quarantine_sz = sz; + } + } + } + printf("%08llx\n", quarantine_sz_main); + printf("%08llx\n", quarantine_sz); + // CHECK: l = 1. + // CHECK: l = 2. + // CHECK-1024: 00006000 + // CHECK-1024: 00001000 + // CHECK-2048: 0000c000 + // CHECK-2048: 00001000 + + s++; + if (t.joinable()) + t.join(); + return 0; +} -- Gitee From 7f2229ec24ced6185b5b4247466ce3fccedc8abf Mon Sep 17 00:00:00 2001 From: meteors117 Date: Thu, 19 Jun 2025 16:17:12 +0800 Subject: [PATCH 3/5] [Huawei][HWASAN] Format write-after-free log. Format the log of write-after-free checked by Quarantine. Signed-off-by: meteors117 --- compiler-rt/lib/hwasan/hwasan_allocator.cpp | 2 +- compiler-rt/lib/hwasan/hwasan_allocator.h | 2 +- compiler-rt/lib/hwasan/hwasan_quarantine.cpp | 33 ++++++------- compiler-rt/lib/hwasan/hwasan_report.cpp | 49 ++++++++++++++++++++ compiler-rt/lib/hwasan/hwasan_report.h | 1 + 5 files changed, 67 insertions(+), 20 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index 46422d02cec7..9d167cc0aa0a 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -332,7 +332,7 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { int aid = meta->thread_id; if (t) { - if (!t->TryPutInQuarantineWithDealloc(reinterpret_cast(aligned_ptr), + if (!t->TryPutInQuarantineWithDealloc(reinterpret_cast(tagged_ptr), TaggedSize(orig_size), alloc_context_id, free_context_id)) { allocator.Deallocate(t->allocator_cache(), aligned_ptr); diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h index dfac62f09cbc..1e5a1cca53ef 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.h +++ b/compiler-rt/lib/hwasan/hwasan_allocator.h @@ -135,7 +135,7 @@ __attribute__((always_inline)) static bool ShouldPrintQuarantineDwillTime() { return flags()->heap_quarantine_max > 0 && flags()->enable_heap_quarantine_debug && (flags()->heap_quarantine_thread_max_count > 0 || - flags()->heap_quarantine_main_thread_max_count > 0); + flags()->heap_quarantine_main_thread_max_count > 0); } // OHOS_LOCAL end diff --git a/compiler-rt/lib/hwasan/hwasan_quarantine.cpp b/compiler-rt/lib/hwasan/hwasan_quarantine.cpp index 6ffbe4980b3a..1808a9ae4225 100644 --- a/compiler-rt/lib/hwasan/hwasan_quarantine.cpp +++ b/compiler-rt/lib/hwasan/hwasan_quarantine.cpp @@ -16,6 +16,7 @@ #include "hwasan_quarantine.h" #include "hwasan_allocator.h" +#include "hwasan_report.h" #include "hwasan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_stackdepot.h" @@ -25,9 +26,8 @@ void HeapQuarantineController::ClearHeapQuarantine(AllocatorCache *cache) { CHECK(cache); if (heap_quarantine_list_) { DeallocateWithHeapQuarantcheck(heap_quarantine_tail_, cache); - size_t sz = RoundUpTo( - heap_quarantine_size_ * sizeof(HeapQuarantine), - GetPageSizeCached()); + size_t sz = RoundUpTo(heap_quarantine_size_ * sizeof(HeapQuarantine), + GetPageSizeCached()); UnmapOrDie(heap_quarantine_list_, sz); heap_quarantine_tail_ = 0; heap_quarantine_list_ = nullptr; @@ -44,9 +44,8 @@ bool HeapQuarantineController::TryPutInQuarantineWithDealloc( if (UNLIKELY(heap_quarantine_size_ <= 0)) return false; if (UNLIKELY(heap_quarantine_list_ == nullptr)) { - size_t sz = RoundUpTo( - heap_quarantine_size_ * sizeof(HeapQuarantine), - GetPageSizeCached()); + size_t sz = RoundUpTo(heap_quarantine_size_ * sizeof(HeapQuarantine), + GetPageSizeCached()); heap_quarantine_list_ = reinterpret_cast( MmapOrDie(sz, "HeapQuarantine", 0)); if (UNLIKELY(heap_quarantine_list_ == nullptr)) { @@ -97,22 +96,20 @@ void HeapQuarantineController::DeallocateWithHeapQuarantcheck( static u64 magic; internal_memset(&magic, flags()->free_fill_byte, sizeof(magic)); for (u32 i = 0; i < free_count; i++) { - u64 *ptrBeg = reinterpret_cast(heap_quarantine_list_[i].ptr); + u64 *tagged_ptr = reinterpret_cast(heap_quarantine_list_[i].ptr); + void *untagged_ptr = UntagPtr(tagged_ptr); + u64 *ptrBeg = reinterpret_cast( + RoundDownTo(reinterpret_cast(untagged_ptr), kShadowAlignment)); if (heap_quarantine_list_[i].s > sizeof(u64)) { if (flags()->max_free_fill_size > 0) { - size_t fill_size = - Min(heap_quarantine_list_[i].s, (size_t)flags()->max_free_fill_size); + size_t fill_size = Min(heap_quarantine_list_[i].s, + (size_t)flags()->max_free_fill_size); for (size_t j = 0; j < fill_size / sizeof(u64); j++) { if (ptrBeg[j] != magic) { - Printf("\nPotential Cause: use-after-free\n"); - Printf( - "ptrBeg was re-written after free %p[%zu], %p " - "%016llx:%016llx, freed by:\n", - ptrBeg, j, &ptrBeg[j], ptrBeg[j], magic); - StackDepotGet(heap_quarantine_list_[i].free_context_id).Print(); - Printf("allocated by:\n"); - StackDepotGet(heap_quarantine_list_[i].alloc_context_id).Print(); - Report("End Hwasan report\n"); + u32 aid = heap_quarantine_list_[i].alloc_context_id; + u32 fid = heap_quarantine_list_[i].free_context_id; + uptr tagged_addr = reinterpret_cast(tagged_ptr); + ReportWriteAfterFree(tagged_addr, aid, fid, j, magic); break; } } diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index a0827639fee4..9ba50ac29f00 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -847,6 +847,55 @@ void ReportMemoryNearRegisters(uptr *frame, uptr sp, uptr pc) { PrintMemoryAroundAddress(proc_maps, -1, pc, flags()->memory_around_register_size, false, true); } + +void ReportWriteAfterFree(uptr tagged_addr, u32 aid, u32 fid, u32 j, + u64 magic) { + ScopedReport R(flags()->halt_on_error); + + uptr untagged_addr = UntagAddr(tagged_addr); + tag_t ptr_tag = GetTagFromPointer(tagged_addr); + tag_t *tag_ptr = nullptr; + tag_t mem_tag = 0; + if (MemIsApp(untagged_addr)) { + tag_ptr = reinterpret_cast(MemToShadow(untagged_addr)); + if (MemIsShadow(reinterpret_cast(tag_ptr))) + mem_tag = *tag_ptr; + else + tag_ptr = nullptr; + } + u64 *ptr_beg = reinterpret_cast(untagged_addr); + Decorator d; + Printf("%s", d.Error()); + const char *toolName = "memory_debug"; + const char *bug_type = "use-after-free"; + const Thread *thread = GetCurrentThread(); + if (thread) { + Report("ERROR: %s: %s on address %p on thread %d\n", toolName, bug_type, + &ptr_beg[j], thread->tid()); + } else { + Report("ERROR: %s: %s on address %p on unknown thread\n", toolName, + bug_type, &ptr_beg[j]); + } + Printf( + "memory was re-written after free at %p[%zu]: %p " + "which filled: %016llx, expect: %016llx, freed by:\n", + ptr_beg, j, &ptr_beg[j], ptr_beg[j], magic); + StackDepotGet(fid).Print(); + Printf("allocated by:\n"); + StackDepotGet(aid).Print(); + Printf("%s", d.Access()); + if (tag_ptr) + Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag); + Printf("%s", d.Default()); + + PrintAddressDescription(tagged_addr, 0, nullptr); + + if (tag_ptr) + PrintTagsAroundAddr(tag_ptr); + + ReportErrorSummary(bug_type, toolName); +} + // OHOS_LOCAL end // See the frame breakdown defined in __hwasan_tag_mismatch (from diff --git a/compiler-rt/lib/hwasan/hwasan_report.h b/compiler-rt/lib/hwasan/hwasan_report.h index 756fea704773..fa742cad4da9 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.h +++ b/compiler-rt/lib/hwasan/hwasan_report.h @@ -33,6 +33,7 @@ void ReportMemoryNearRegisters(uptr *registers_frame, uptr sp, uptr pc); void PrintMemoryAroundAddress(MemoryMappingLayout &proc_maps, int reg_num, uptr addr, uptr len, bool is_sp = false, bool is_pc = false); +void ReportWriteAfterFree(uptr tagged_addr, u32 aid, u32 fid, u32 j, u64 magic); // OHOS_LOCAL end void ReportAtExitStatistics(); -- Gitee From dc15f0d4efe173731cafb7ba62407b34f357ebfa Mon Sep 17 00:00:00 2001 From: meteors117 Date: Thu, 19 Jun 2025 16:19:06 +0800 Subject: [PATCH 4/5] [Huawei][HWASAN] Add Quarantine check test case. Add a test case to check the write after free fault and check the log format. Signed-off-by: meteors117 --- .../TestCases/write_after_free_quarantine.cpp | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 compiler-rt/test/hwasan/TestCases/write_after_free_quarantine.cpp diff --git a/compiler-rt/test/hwasan/TestCases/write_after_free_quarantine.cpp b/compiler-rt/test/hwasan/TestCases/write_after_free_quarantine.cpp new file mode 100644 index 000000000000..65ad90c1bf2c --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/write_after_free_quarantine.cpp @@ -0,0 +1,39 @@ +// Check the heap_quarantine size correctly. +// RUN: %clangxx_hwasan %s -o %t +// RUN: %env_hwasan_opts=max_free_fill_size=256:heap_quarantine_max=1025:heap_quarantine_main_thread_max_count=16\ +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK + +#include +#include +#include + +static const int kSize = 1 << 4; +static const int kQuarantineCount = 16; +static volatile unsigned long long *sink; +static unsigned long long *x; +static char *y; + +void malloc_and_free() { + for (int i = 0; i < kQuarantineCount; i++) { + y = (char *)malloc(kSize); + free(y); + } +} + +// Write the freed ptr in a non-hwasan function so that we don't detect the +// stores as OOB. +__attribute__((no_sanitize("hwaddress"))) int main(int argc, char **argv) { + __hwasan_enable_allocator_tagging(); + x = (unsigned long long *)malloc(sizeof(unsigned long long)); + sink = x; + free(x); + *sink = 0x42; + malloc_and_free(); + // CHECK: ==write_after_free_quarantine.cpp.tmp=={{.*}}==ERROR: memory_debug: use-after-free on address {{.*}} on thread {{.*}} + // CHECK: memory was re-written after free at {{.*}}[0]: {{.*}} which filled: {{.*}}, expect: {{.*}}, freed by: + // CHECK: {{.*}}in main {{.*}}write_after_free_quarantine.cpp:[[@LINE-5]] + // CHECK: allocated by: + // CHECK: {{.*}}in main {{.*}}write_after_free_quarantine.cpp:[[@LINE-9]] + // CHECK: tags: {{.*}}/{{.*}} (ptr/mem) + return 0; +} \ No newline at end of file -- Gitee From f236b4633c74d53e39a412bdc60fcafb0817e454 Mon Sep 17 00:00:00 2001 From: meteors117 Date: Fri, 18 Apr 2025 11:52:49 +0800 Subject: [PATCH 5/5] [Compiler-rt][HWASAN] memory_debug initialize. The size of malloc_fill and free_fill can be set by options, also the max size of freed memory. When the value be set out of the range, set it to default value. Signed-off-by: meteors117 --- compiler-rt/lib/hwasan/hwasan.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/hwasan/hwasan.cpp b/compiler-rt/lib/hwasan/hwasan.cpp index 84b4ebd6f246..a25646e85708 100644 --- a/compiler-rt/lib/hwasan/hwasan.cpp +++ b/compiler-rt/lib/hwasan/hwasan.cpp @@ -425,9 +425,18 @@ __attribute__((constructor(0))) void __hwasan_init() { // OHOS_LOCAL begin if (flags()->memory_debug) { - flags()->max_malloc_fill_size = 256; - flags()->max_free_fill_size = 256; - flags()->heap_quarantine_max = 1024 + 1; + if (flags()->max_malloc_fill_size <= 0 || + flags()->max_malloc_fill_size > 1024) { + flags()->max_malloc_fill_size = 256; + } + if (flags()->max_free_fill_size <= 0 || + flags()->max_free_fill_size > 1024) { + flags()->max_free_fill_size = 256; + } + if (flags()->heap_quarantine_max < 0 || + flags()->heap_quarantine_max > 4096) { + flags()->heap_quarantine_max = 1024 + 1; + } } // OHOS_LOCAL end -- Gitee