diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp index 9e66f77217ec6..3a55c2af65653 100644 --- a/compiler-rt/lib/asan/asan_allocator.cpp +++ b/compiler-rt/lib/asan/asan_allocator.cpp @@ -21,6 +21,7 @@ #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" +#include "asan_suppressions.h" #include "asan_thread.h" #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_allocator_checks.h" @@ -732,7 +733,8 @@ struct Allocator { if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return; if (m->alloc_type != alloc_type) { - if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) { + if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire) && + !IsAllocDeallocMismatchSuppressed(stack)) { ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, (AllocType)alloc_type); } diff --git a/compiler-rt/lib/asan/asan_suppressions.cpp b/compiler-rt/lib/asan/asan_suppressions.cpp index 94289d14d7e78..30de775235800 100644 --- a/compiler-rt/lib/asan/asan_suppressions.cpp +++ b/compiler-rt/lib/asan/asan_suppressions.cpp @@ -26,9 +26,10 @@ static const char kInterceptorName[] = "interceptor_name"; static const char kInterceptorViaFunction[] = "interceptor_via_fun"; static const char kInterceptorViaLibrary[] = "interceptor_via_lib"; static const char kODRViolation[] = "odr_violation"; +static const char kAllocDeallocMismatch[] = "alloc_dealloc_mismatch"; static const char *kSuppressionTypes[] = { kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary, - kODRViolation}; + kODRViolation, kAllocDeallocMismatch}; SANITIZER_INTERFACE_WEAK_DEF(const char *, __asan_default_suppressions, void) { return ""; @@ -62,6 +63,44 @@ bool IsODRViolationSuppressed(const char *global_var_name) { return suppression_ctx->Match(global_var_name, kODRViolation, &s); } +bool IsAddrSuppressed(const char *suppression, Symbolizer *symbolizer, + uptr addr) { + CHECK(suppression_ctx); + CHECK(suppression_ctx->HasSuppressionType(suppression)); + CHECK(symbolizer); + SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr)); + const SymbolizedStack *frames = symbolized_stack.get(); + CHECK(frames); + for (const SymbolizedStack *cur = frames; cur; cur = cur->next) { + const char *function_name = cur->info.function; + if (!function_name) { + continue; + } + // Match suppressions. + Suppression *s; + if (suppression_ctx->Match(function_name, suppression, &s)) { + return true; + } + } + return false; +} + +bool IsAllocDeallocMismatchSuppressed(const StackTrace *stack) { + CHECK(suppression_ctx); + if (!suppression_ctx->HasSuppressionType(kAllocDeallocMismatch)) { + return false; + } + Symbolizer *symbolizer = Symbolizer::GetOrInit(); + for (uptr i = 0; i < stack->size && stack->trace[i]; i++) { + uptr addr = stack->trace[i]; + // Match "alloc_dealloc_mismatch" suppressions. + if (IsAddrSuppressed(kAllocDeallocMismatch, symbolizer, addr)) { + return true; + } + } + return false; +} + bool IsStackTraceSuppressed(const StackTrace *stack) { if (!HaveStackTraceBasedSuppressions()) return false; @@ -80,19 +119,9 @@ bool IsStackTraceSuppressed(const StackTrace *stack) { } if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { - SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr)); - const SymbolizedStack *frames = symbolized_stack.get(); - CHECK(frames); - for (const SymbolizedStack *cur = frames; cur; cur = cur->next) { - const char *function_name = cur->info.function; - if (!function_name) { - continue; - } - // Match "interceptor_via_fun" suppressions. - if (suppression_ctx->Match(function_name, kInterceptorViaFunction, - &s)) { - return true; - } + // Match "interceptor_via_func" suppressions. + if (IsAddrSuppressed(kInterceptorViaFunction, symbolizer, addr)) { + return true; } } } diff --git a/compiler-rt/lib/asan/asan_suppressions.h b/compiler-rt/lib/asan/asan_suppressions.h index 121d4ddf18756..4613a362f28e4 100644 --- a/compiler-rt/lib/asan/asan_suppressions.h +++ b/compiler-rt/lib/asan/asan_suppressions.h @@ -23,6 +23,7 @@ bool IsInterceptorSuppressed(const char *interceptor_name); bool HaveStackTraceBasedSuppressions(); bool IsStackTraceSuppressed(const StackTrace *stack); bool IsODRViolationSuppressed(const char *global_var_name); +bool IsAllocDeallocMismatchSuppressed(const StackTrace *stack); } // namespace __asan diff --git a/compiler-rt/test/asan/TestCases/suppressions-alloc-dealloc-mismatch.cpp b/compiler-rt/test/asan/TestCases/suppressions-alloc-dealloc-mismatch.cpp new file mode 100644 index 0000000000000..fe88a5d0c9bf1 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/suppressions-alloc-dealloc-mismatch.cpp @@ -0,0 +1,26 @@ +// Check that without suppressions, we catch the issue. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s + +// RUN: echo "alloc_dealloc_mismatch:function" > %t.supp +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: %clangxx_asan -O3 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s + +#include +#include +#include + +void function() { + char *a = (char *)malloc(6); + a[0] = '\0'; + size_t len = strlen(a); + delete a; // BOOM + fprintf(stderr, "strlen ignored, len = %zu\n", len); +} + +int main() { function(); } + +// CHECK-CRASH: AddressSanitizer: alloc-dealloc-mismatch +// CHECK-CRASH-NOT: strlen ignored +// CHECK-IGNORE-NOT: AddressSanitizer: alloc-dealloc-mismatch +// CHECK-IGNORE: strlen ignored