Skip to content

Commit 6b654a0

Browse files
authored
[sanitizer] Support "alloc_dealloc_mismatch" suppressions (#124197)
This adds a stack-based suppression for alloc-dealloc-mismatch violations, using the function name to match.
1 parent 98d6dd3 commit 6b654a0

File tree

4 files changed

+73
-15
lines changed

4 files changed

+73
-15
lines changed

compiler-rt/lib/asan/asan_allocator.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "asan_poisoning.h"
2222
#include "asan_report.h"
2323
#include "asan_stack.h"
24+
#include "asan_suppressions.h"
2425
#include "asan_thread.h"
2526
#include "lsan/lsan_common.h"
2627
#include "sanitizer_common/sanitizer_allocator_checks.h"
@@ -732,7 +733,8 @@ struct Allocator {
732733
if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return;
733734

734735
if (m->alloc_type != alloc_type) {
735-
if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
736+
if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire) &&
737+
!IsAllocDeallocMismatchSuppressed(stack)) {
736738
ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
737739
(AllocType)alloc_type);
738740
}

compiler-rt/lib/asan/asan_suppressions.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ static const char kInterceptorName[] = "interceptor_name";
2626
static const char kInterceptorViaFunction[] = "interceptor_via_fun";
2727
static const char kInterceptorViaLibrary[] = "interceptor_via_lib";
2828
static const char kODRViolation[] = "odr_violation";
29+
static const char kAllocDeallocMismatch[] = "alloc_dealloc_mismatch";
2930
static const char *kSuppressionTypes[] = {
3031
kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary,
31-
kODRViolation};
32+
kODRViolation, kAllocDeallocMismatch};
3233

3334
SANITIZER_INTERFACE_WEAK_DEF(const char *, __asan_default_suppressions, void) {
3435
return "";
@@ -62,6 +63,44 @@ bool IsODRViolationSuppressed(const char *global_var_name) {
6263
return suppression_ctx->Match(global_var_name, kODRViolation, &s);
6364
}
6465

66+
bool IsAddrSuppressed(const char *suppression, Symbolizer *symbolizer,
67+
uptr addr) {
68+
CHECK(suppression_ctx);
69+
CHECK(suppression_ctx->HasSuppressionType(suppression));
70+
CHECK(symbolizer);
71+
SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr));
72+
const SymbolizedStack *frames = symbolized_stack.get();
73+
CHECK(frames);
74+
for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
75+
const char *function_name = cur->info.function;
76+
if (!function_name) {
77+
continue;
78+
}
79+
// Match suppressions.
80+
Suppression *s;
81+
if (suppression_ctx->Match(function_name, suppression, &s)) {
82+
return true;
83+
}
84+
}
85+
return false;
86+
}
87+
88+
bool IsAllocDeallocMismatchSuppressed(const StackTrace *stack) {
89+
CHECK(suppression_ctx);
90+
if (!suppression_ctx->HasSuppressionType(kAllocDeallocMismatch)) {
91+
return false;
92+
}
93+
Symbolizer *symbolizer = Symbolizer::GetOrInit();
94+
for (uptr i = 0; i < stack->size && stack->trace[i]; i++) {
95+
uptr addr = stack->trace[i];
96+
// Match "alloc_dealloc_mismatch" suppressions.
97+
if (IsAddrSuppressed(kAllocDeallocMismatch, symbolizer, addr)) {
98+
return true;
99+
}
100+
}
101+
return false;
102+
}
103+
65104
bool IsStackTraceSuppressed(const StackTrace *stack) {
66105
if (!HaveStackTraceBasedSuppressions())
67106
return false;
@@ -80,19 +119,9 @@ bool IsStackTraceSuppressed(const StackTrace *stack) {
80119
}
81120

82121
if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
83-
SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr));
84-
const SymbolizedStack *frames = symbolized_stack.get();
85-
CHECK(frames);
86-
for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
87-
const char *function_name = cur->info.function;
88-
if (!function_name) {
89-
continue;
90-
}
91-
// Match "interceptor_via_fun" suppressions.
92-
if (suppression_ctx->Match(function_name, kInterceptorViaFunction,
93-
&s)) {
94-
return true;
95-
}
122+
// Match "interceptor_via_func" suppressions.
123+
if (IsAddrSuppressed(kInterceptorViaFunction, symbolizer, addr)) {
124+
return true;
96125
}
97126
}
98127
}

compiler-rt/lib/asan/asan_suppressions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ bool IsInterceptorSuppressed(const char *interceptor_name);
2323
bool HaveStackTraceBasedSuppressions();
2424
bool IsStackTraceSuppressed(const StackTrace *stack);
2525
bool IsODRViolationSuppressed(const char *global_var_name);
26+
bool IsAllocDeallocMismatchSuppressed(const StackTrace *stack);
2627

2728
} // namespace __asan
2829

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Check that without suppressions, we catch the issue.
2+
// RUN: %clangxx_asan -O0 %s -o %t
3+
// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
4+
5+
// RUN: echo "alloc_dealloc_mismatch:function" > %t.supp
6+
// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
7+
// RUN: %clangxx_asan -O3 %s -o %t && %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
8+
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
13+
void function() {
14+
char *a = (char *)malloc(6);
15+
a[0] = '\0';
16+
size_t len = strlen(a);
17+
delete a; // BOOM
18+
fprintf(stderr, "strlen ignored, len = %zu\n", len);
19+
}
20+
21+
int main() { function(); }
22+
23+
// CHECK-CRASH: AddressSanitizer: alloc-dealloc-mismatch
24+
// CHECK-CRASH-NOT: strlen ignored
25+
// CHECK-IGNORE-NOT: AddressSanitizer: alloc-dealloc-mismatch
26+
// CHECK-IGNORE: strlen ignored

0 commit comments

Comments
 (0)