[asan] Suppress duplicated errors in ASan recovery mode.
authorYury Gribov <y.gribov@samsung.com>
Thu, 10 Dec 2015 08:08:53 +0000 (08:08 +0000)
committerYury Gribov <y.gribov@samsung.com>
Thu, 10 Dec 2015 08:08:53 +0000 (08:08 +0000)
Patch by Max Ostapenko.

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

llvm-svn: 255228

compiler-rt/lib/asan/asan_report.cc
compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
compiler-rt/test/asan/TestCases/Posix/halt_on_error-signals.c
compiler-rt/test/asan/TestCases/Posix/halt_on_error-torture.cc
compiler-rt/test/asan/TestCases/halt_on_error_suppress_equal_pcs.cc [new file with mode: 0644]

index de1d1fb..b9e654e 100644 (file)
@@ -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;
@@ -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.
index 3b685db..a94a681 100644 (file)
@@ -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).")
index fdc718d..60916f6 100644 (file)
@@ -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
 
index d4f2115..019f7d1 100644 (file)
@@ -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
diff --git a/compiler-rt/test/asan/TestCases/halt_on_error_suppress_equal_pcs.cc b/compiler-rt/test/asan/TestCases/halt_on_error_suppress_equal_pcs.cc
new file mode 100644 (file)
index 0000000..98b0348
--- /dev/null
@@ -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;
+}
+