0
0
mirror of https://github.com/llvm/llvm-project.git synced 2025-04-21 10:16:49 +00:00

[sanitizer] Support "alloc_dealloc_mismatch" suppressions ()

This adds a stack-based suppression for alloc-dealloc-mismatch
violations, using the function name to match.
This commit is contained in:
andrewjcg 2025-01-28 18:04:12 -08:00 committed by GitHub
parent 98d6dd3988
commit 6b654a09c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 15 deletions

@ -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);
}

@ -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;
}
}
}

@ -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

@ -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