[ASan] reimplement strdup() interceptor to get nicer stack traces for memory chunks allocated there

git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@184546 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc
index 7643271..3060665 100644
--- a/lib/asan/asan_interceptors.cc
+++ b/lib/asan/asan_interceptors.cc
@@ -461,21 +461,16 @@
 
 #if ASAN_INTERCEPT_STRDUP
 INTERCEPTOR(char*, strdup, const char *s) {
-#if SANITIZER_MAC
-  // FIXME: because internal_strdup() uses InternalAlloc(), which currently
-  // just calls malloc() on Mac, we can't use internal_strdup() with the
-  // dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc
-  // starts using mmap() instead.
-  // See also http://code.google.com/p/address-sanitizer/issues/detail?id=123.
-  if (!asan_inited) return REAL(strdup)(s);
-#endif
   if (!asan_inited) return internal_strdup(s);
   ENSURE_ASAN_INITED();
+  uptr length = REAL(strlen)(s);
   if (flags()->replace_str) {
-    uptr length = REAL(strlen)(s);
     ASAN_READ_RANGE(s, length + 1);
   }
-  return REAL(strdup)(s);
+  GET_STACK_TRACE_MALLOC;
+  void *new_mem = asan_malloc(length + 1, &stack);
+  REAL(memcpy)(new_mem, s, length + 1);
+  return reinterpret_cast<char*>(new_mem);
 }
 #endif
 
diff --git a/lib/asan/lit_tests/TestCases/strdup_oob_test.cc b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
new file mode 100644
index 0000000..f8366dd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s
+
+#include <string.h>
+
+char kString[] = "foo";
+
+int main(int argc, char **argv) {
+  char *copy = strdup(kString);
+  int x = copy[4 + argc];  // BOOM
+  // CHECK: AddressSanitizer: heap-buffer-overflow
+  // CHECK: #0 {{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-2]]
+  // CHECK: allocated by thread T{{.*}} here:
+  // CHECK: #0 {{.*}}strdup
+  // CHECK: strdup_oob_test.cc:[[@LINE-6]]
+  return x;
+}