Skip to content

Commit

Permalink
[asan] Suppress duplicated errors in ASan recovery mode.
Browse files Browse the repository at this point in the history
Patch by Max Ostapenko.

Differential Revision: http://reviews.llvm.org/D15080

llvm-svn: 255228
  • Loading branch information
Yury Gribov committed Dec 10, 2015
1 parent a3c0e8e commit 6bfade1
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 2 deletions.
17 changes: 17 additions & 0 deletions compiler-rt/lib/asan/asan_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ static void (*error_report_callback)(const char*);
static char *error_message_buffer = nullptr;
static uptr error_message_buffer_pos = 0;
static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
static const unsigned kAsanBuggyPcPoolSize = 25;
static __sanitizer::atomic_uint64_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];

struct ReportData {
uptr pc;
Expand Down Expand Up @@ -1000,8 +1002,23 @@ void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
DescribeHeapAddress(addr, 1);
}

// -------------- SuppressErrorReport -------------- {{{1
// Avoid error reports duplicating for ASan recover mode.
static bool SuppressErrorReport(uptr pc) {
if (!common_flags()->suppress_equal_pcs) return false;
for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
u64 cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
pc, memory_order_relaxed))
return false;
if (cmp == pc) return true;
}
Die();
}

void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal) {
if (!fatal && SuppressErrorReport(pc)) return;
ENABLE_FRAME_POINTER;

// Optimization experiments.
Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,6 @@ COMMON_FLAG(
bool, abort_on_error, SANITIZER_MAC,
"If set, the tool calls abort() instead of _exit() after printing the "
"error report.")
COMMON_FLAG(bool, suppress_equal_pcs, true,
"Deduplicate multiple reports for single source location in "
"halt_on_error=false mode (asan only).")
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// RUN: %clang_asan -fsanitize-recover=address -pthread %s -o %t
//
// RUN: rm -f %t.log
// RUN: %env_asan_opts=halt_on_error=false %run %t 100 >%t.log 2>&1 || true
// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 100 >%t.log 2>&1 || true
// Collision will almost always get triggered but we still need to check the unlikely case:
// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < %t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s < %t.log

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
//
// RUN: %clangxx_asan -fsanitize-recover=address -pthread %s -o %t
//
// RUN: %env_asan_opts=halt_on_error=false %run %t 1 10 >1.txt 2>&1
// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 1 10 >1.txt 2>&1
// RUN: FileCheck %s < 1.txt
// RUN: [ $(grep -c 'ERROR: AddressSanitizer: use-after-poison' 1.txt) -eq 10 ]
// RUN: FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt
//
// Collisions are unlikely but still possible so we need the ||.
// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 10 20 >10.txt 2>&1 || true
// This one is racy although _very_ unlikely to fail:
// RUN: FileCheck %s < 10.txt
// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 1.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt
//
// Collisions are unlikely but still possible so we need the ||.
// RUN: %env_asan_opts=halt_on_error=false %run %t 10 20 >10.txt 2>&1 || true
// This one is racy although _very_ unlikely to fail:
// RUN: FileCheck %s < 10.txt
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Test reports dedupication for recovery mode.
//
// RUN: %clang_asan -fsanitize-recover=address %s -o %t
//
// Check for reports dedupication.
// RUN: %env_asan_opts=halt_on_error=false %run %t 2>&1 | FileCheck %s
//
// Check that we die after reaching different reports number threshold.
// RUN: %env_asan_opts=halt_on_error=false not %run %t 1 > %t1.log 2>&1
// RUN: [ $(grep -c 'ERROR: AddressSanitizer: stack-buffer-overflow' %t1.log) -eq 25 ]
//
// Check suppress_equal_pcs=true behavior is equal to default one.
// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=true %run %t 2>&1 | FileCheck %s
//
// Check suppress_equal_pcs=false behavior isn't equal to default one.
// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t > %t2.log 2>&1
// RUN: [ $(grep -c 'ERROR: AddressSanitizer: stack-buffer-overflow' %t2.log) -eq 30 ]

#define ACCESS_ARRAY_FIVE_ELEMENTS(array, i) \
array[i] = i; \
array[i + 1] = i + 1; \
array[i + 2] = i + 2; \
array[i + 3] = i + 3; \
array[i + 4] = i + 4; \

volatile int ten = 10;
unsigned kNumIterations = 10;

int main(int argc, char **argv) {
char a[10];
char b[10];

if (argc == 1) {
for (int i = 0; i < kNumIterations; ++i) {
// CHECK: READ of size 1
volatile int res = a[ten + i];
// CHECK: WRITE of size 1
a[i + ten] = res + 3;
// CHECK: READ of size 1
res = a[ten + i];
// CHECK-NOT: ERROR
}
} else {
for (int i = 0; i < kNumIterations; ++i) {
ACCESS_ARRAY_FIVE_ELEMENTS(a, ten);
ACCESS_ARRAY_FIVE_ELEMENTS(a, ten + 5);
ACCESS_ARRAY_FIVE_ELEMENTS(a, ten + 10);
ACCESS_ARRAY_FIVE_ELEMENTS(b, ten);
ACCESS_ARRAY_FIVE_ELEMENTS(b, ten + 5);
ACCESS_ARRAY_FIVE_ELEMENTS(b, ten + 10);
}
}
return 0;
}

0 comments on commit 6bfade1

Please sign in to comment.