Skip to content

[sanitizer] Support "alloc_dealloc_mismatch" suppressions #124197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion compiler-rt/lib/asan/asan_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
}
Expand Down
57 changes: 43 additions & 14 deletions compiler-rt/lib/asan/asan_suppressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/asan/asan_suppressions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>

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
Loading