[asan] Fix bug where suppression of overlapping accesses was ignored on
authorDan Liew <dan@su-root.co.uk>
Thu, 8 Mar 2018 21:50:22 +0000 (21:50 +0000)
committerDan Liew <dan@su-root.co.uk>
Thu, 8 Mar 2018 21:50:22 +0000 (21:50 +0000)
`strcpy()`, `strncpy()`, `strcat()`, and `strncat()`.

rdar://problem/35576899

Differential Revision: https://reviews.llvm.org/D43702

llvm-svn: 327068

compiler-rt/lib/asan/asan_interceptors_memintrinsics.h
compiler-rt/test/asan/TestCases/strcat-overlap.cc [new file with mode: 0644]
compiler-rt/test/asan/TestCases/strcpy-overlap.cc [new file with mode: 0644]
compiler-rt/test/asan/TestCases/strncat-overlap.cc [new file with mode: 0644]
compiler-rt/test/asan/TestCases/strncpy-overlap.cc [new file with mode: 0644]

index 5a8339a..a071e8f 100644 (file)
@@ -133,15 +133,22 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
                                  const char *offset2, uptr length2) {
   return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
 }
-#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
-  const char *offset1 = (const char*)_offset1; \
-  const char *offset2 = (const char*)_offset2; \
-  if (RangesOverlap(offset1, length1, offset2, length2)) { \
-    GET_STACK_TRACE_FATAL_HERE; \
-    ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
-                                            offset2, length2, &stack); \
-  } \
-} while (0)
+#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2)   \
+  do {                                                                     \
+    const char *offset1 = (const char *)_offset1;                          \
+    const char *offset2 = (const char *)_offset2;                          \
+    if (RangesOverlap(offset1, length1, offset2, length2)) {               \
+      GET_STACK_TRACE_FATAL_HERE;                                          \
+      bool suppressed = IsInterceptorSuppressed(name);                     \
+      if (!suppressed && HaveStackTraceBasedSuppressions()) {              \
+        suppressed = IsStackTraceSuppressed(&stack);                       \
+      }                                                                    \
+      if (!suppressed) {                                                   \
+        ReportStringFunctionMemoryRangesOverlap(name, offset1, length1,    \
+                                                offset2, length2, &stack); \
+      }                                                                    \
+    }                                                                      \
+  } while (0)
 
 }  // namespace __asan
 
diff --git a/compiler-rt/test/asan/TestCases/strcat-overlap.cc b/compiler-rt/test/asan/TestCases/strcat-overlap.cc
new file mode 100644 (file)
index 0000000..96b102a
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O1 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+
+#include <string.h>
+
+
+// Don't inline function otherwise stacktrace changes.
+__attribute__((noinline)) void bad_function() {
+  char buffer[] = "hello\0XXX";
+  // CHECK: strcat-param-overlap: memory ranges
+  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
+  // CHECK: {{#0 0x.* in .*strcat}}
+  // CHECK: {{#1 0x.* in bad_function.*strcat-overlap.cc:}}[[@LINE+2]]
+  // CHECK: {{#2 0x.* in main .*strcat-overlap.cc:}}[[@LINE+5]]
+  strcat(buffer, buffer + 1); // BOOM
+}
+
+int main(int argc, char **argv) {
+  bad_function();
+  return 0;
+}
diff --git a/compiler-rt/test/asan/TestCases/strcpy-overlap.cc b/compiler-rt/test/asan/TestCases/strcpy-overlap.cc
new file mode 100644 (file)
index 0000000..5c71e79
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O1 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strcpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+
+#include <string.h>
+
+
+// Don't inline function otherwise stacktrace changes.
+__attribute__((noinline)) void bad_function() {
+  char buffer[] = "hello";
+  // CHECK: strcpy-param-overlap: memory ranges
+  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
+  // CHECK: {{#0 0x.* in .*strcpy}}
+  // CHECK: {{#1 0x.* in bad_function.*strcpy-overlap.cc:}}[[@LINE+2]]
+  // CHECK: {{#2 0x.* in main .*strcpy-overlap.cc:}}[[@LINE+5]]
+  strcpy(buffer, buffer + 1); // BOOM
+}
+
+int main(int argc, char **argv) {
+  bad_function();
+  return 0;
+}
diff --git a/compiler-rt/test/asan/TestCases/strncat-overlap.cc b/compiler-rt/test/asan/TestCases/strncat-overlap.cc
new file mode 100644 (file)
index 0000000..89bc64c
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O1 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncat" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+
+#include <string.h>
+
+
+// Don't inline function otherwise stacktrace changes.
+__attribute__((noinline)) void bad_function() {
+  char buffer[] = "hello\0XXX";
+  // CHECK: strncat-param-overlap: memory ranges
+  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
+  // CHECK: {{#0 0x.* in .*strncat}}
+  // CHECK: {{#1 0x.* in bad_function.*strncat-overlap.cc:}}[[@LINE+2]]
+  // CHECK: {{#2 0x.* in main .*strncat-overlap.cc:}}[[@LINE+5]]
+  strncat(buffer, buffer + 1, 3); // BOOM
+}
+
+int main(int argc, char **argv) {
+  bad_function();
+  return 0;
+}
diff --git a/compiler-rt/test/asan/TestCases/strncpy-overlap.cc b/compiler-rt/test/asan/TestCases/strncpy-overlap.cc
new file mode 100644 (file)
index 0000000..51bf465
--- /dev/null
@@ -0,0 +1,46 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O1 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+//
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+// RUN: echo "interceptor_name:strncpy" > %t.supp
+// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
+
+#include <string.h>
+
+
+// Don't inline function otherwise stacktrace changes.
+__attribute__((noinline)) void bad_function() {
+  char buffer[] = "hello";
+  // CHECK: strncpy-param-overlap: memory ranges
+  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
+  // CHECK: {{#0 0x.* in .*strncpy}}
+  // CHECK: {{#1 0x.* in bad_function.*strncpy-overlap.cc:}}[[@LINE+2]]
+  // CHECK: {{#2 0x.* in main .*strncpy-overlap.cc:}}[[@LINE+5]]
+  strncpy(buffer, buffer + 1, 5); // BOOM
+}
+
+int main(int argc, char **argv) {
+  bad_function();
+  return 0;
+}