If the program is linked to a dynamic ASan runtime which is not present in DYLD_INSERT_LIBRARIES
(which, in turn, is required for our interceptors to take effect), re-exec the program with
DYLD_INSERT_LIBRARIES set.


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@162547 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/asan/Makefile.old b/lib/asan/Makefile.old
index 4ab80e2..a6f496d 100644
--- a/lib/asan/Makefile.old
+++ b/lib/asan/Makefile.old
@@ -60,6 +60,7 @@
 CLANG_FLAGS=
 CLANG_VERSION=3.2
 CLANG_BUILD=$(ROOT)/../../../../build/Release+Asserts
+CLANG_BUILD=/Users/glider/src/asan/llvm/llvm_cmake_build
 CLANG_CC=$(CLANG_BUILD)/bin/clang $(CLANG_FLAGS)
 CLANG_CXX=$(CLANG_BUILD)/bin/clang++ $(CLANG_FLAGS)
 FILE_CHECK=$(CLANG_BUILD)/bin/FileCheck
@@ -146,7 +147,9 @@
 		-mllvm -asan-use-after-return=$(ASAN_UAR) \
 		$(COMMON_ASAN_DEFINES)
 
-CLANG_ASAN_LD=$(CLANG_CXX) -faddress-sanitizer
+#CLANG_ASAN_LD=$(CLANG_CXX) -faddress-sanitizer
+#CLANG_ASAN_LD=$(CLANG_CXX) -L/Users/glider/src/asan/llvm/llvm_cmake_build/projects/compiler-rt/lib/asan/lib -lclang_rt.asan_osx_dynamic #-faddress-sanitizer
+CLANG_ASAN_LD=$(CLANG_CXX) -faddress-sanitizer -faddress-sanitizer-dynamic-runtime
 
 GCC_ASAN_PATH=SET_FROM_COMMAND_LINE
 GCC_ASAN_CXX=$(GCC_ASAN_PATH)/g++ \
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index d58a833..8b5c11c 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -84,6 +84,9 @@
   // By default, disable core dumper on 64-bit - it makes little sense
   // to dump 16T+ core.
   bool disable_core;
+  // Allow the tool to re-exec the program. This may interfere badly with the
+  // debugger.
+  bool allow_reexec;
   // Strips this prefix from file paths in error reports.
   const char *strip_path_prefix;
 };
diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h
index 3281692..3b3e90e 100644
--- a/lib/asan/asan_interceptors.h
+++ b/lib/asan/asan_interceptors.h
@@ -24,6 +24,7 @@
 DECLARE_REAL(uptr, strlen, const char *s)
 DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
 DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
+DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
 struct sigaction;
 DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
                              struct sigaction *oldact)
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 4ed138c..d72a556 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -100,6 +100,7 @@
 
 void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
 
+void MaybeReexec();
 bool AsanInterceptsSignal(int signum);
 void SetAlternateSignalStack();
 void UnsetAlternateSignalStack();
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 9a3d6bd..ddaefb2 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -40,6 +40,10 @@
 
 namespace __asan {
 
+void MaybeReexec() {
+  // No need to re-exec on Linux.
+}
+
 void *AsanDoesNotSupportStaticLinkage() {
   // This will fail to link with -static.
   return &_DYNAMIC;  // defined in link.h
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 8e8b664..4a5b6ec 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -23,7 +23,8 @@
 #include "asan_thread_registry.h"
 #include "sanitizer_common/sanitizer_libc.h"
 
-#include <crt_externs.h>  // for _NSGetEnviron
+#include <crt_externs.h>  // for _NSGetArgv
+#include <dlfcn.h>  // for dladdr()
 #include <mach-o/dyld.h>
 #include <mach-o/loader.h>
 #include <sys/mman.h>
@@ -83,6 +84,42 @@
   return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
 }
 
+extern "C"
+void __asan_init();
+
+static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
+
+void MaybeReexec() {
+  if (!flags()->allow_reexec) return;
+#if MAC_INTERPOSE_FUNCTIONS
+  // If the program is linked with the dynamic ASan runtime library, make sure
+  // the library is preloaded so that the wrappers work. If it is not, set
+  // DYLD_INSERT_LIBRARIES and re-exec ourselves.
+  Dl_info info;
+  int result = dladdr((void*)__asan_init, &info);
+  const char *dyld_insert_libraries = GetEnv(kDyldInsertLibraries);
+  if (!dyld_insert_libraries ||
+      !REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
+    // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
+    // library.
+    char program_name[1024];
+    uint32_t buf_size = sizeof(program_name);
+    _NSGetExecutablePath(program_name, &buf_size);
+    // Ok to use setenv() since the wrappers don't depend on the value of
+    // asan_inited.
+    setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
+    if (flags()->verbosity >= 1) {
+      Report("exec()-ing the program with\n");
+      Report("%s=%s\n", kDyldInsertLibraries, info.dli_fname);
+      Report("to enable ASan wrappers.\n");
+      Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
+    }
+    execv(program_name, *_NSGetArgv());
+  }
+#endif  // MAC_INTERPOSE_FUNCTIONS
+  // If we're not using the dynamic runtime, do nothing.
+}
+
 // No-op. Mac does not support static linkage anyway.
 void *AsanDoesNotSupportStaticLinkage() {
   return 0;
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 661a078..70b1801 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -101,6 +101,7 @@
   ParseFlag(str, &f->atexit, "atexit");
   ParseFlag(str, &f->disable_core, "disable_core");
   ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
+  ParseFlag(str, &f->allow_reexec, "allow_reexec");
 }
 
 extern "C" {
@@ -137,6 +138,7 @@
   f->atexit = false;
   f->disable_core = (__WORDSIZE == 64);
   f->strip_path_prefix = "";
+  f->allow_reexec = true;
 
   // Override from user-specified string.
   ParseFlagsFromString(f, __asan_default_options());
@@ -293,7 +295,8 @@
   // Make sure we are not statically linked.
   AsanDoesNotSupportStaticLinkage();
 
-  // Initialize flags.
+  // Initialize flags. This must be done early, because most of the
+  // initialization steps look at flags().
   const char *options = GetEnv("ASAN_OPTIONS");
   InitializeFlags(flags(), options);
 
@@ -301,6 +304,10 @@
     Report("Parsed ASAN_OPTIONS: %s\n", options);
   }
 
+  // Re-exec ourselves if we need to set additional env or command line args.
+  MaybeReexec();
+
+
   if (flags()->atexit) {
     Atexit(asan_atexit);
   }
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index d50ee14..5d41644 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -153,6 +153,10 @@
 }
 
 // ---------------------- Various stuff ---------------- {{{1
+void MaybeReexec() {
+  // No need to re-exec on Windows.
+}
+
 void *AsanDoesNotSupportStaticLinkage() {
 #if defined(_DEBUG)
 #error Please build the runtime with a non-debug CRT: /MD or /MT