Index: lib/asan/asan_linux.cc =================================================================== --- lib/asan/asan_linux.cc +++ lib/asan/asan_linux.cc @@ -111,14 +111,16 @@ } void AsanCheckDynamicRTPrereqs() { - // Ensure that dynamic RT is the first DSO in the list - const char *first_dso_name = 0; - dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); - if (first_dso_name && !IsDynamicRTName(first_dso_name)) { - Report("ASan runtime does not come first in initial library list; " - "you should either link runtime to your application or " - "manually preload it with LD_PRELOAD.\n"); - Die(); + if (ASAN_DYNAMIC) { + // Ensure that dynamic RT is the first DSO in the list + const char *first_dso_name = 0; + dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); + if (first_dso_name && !IsDynamicRTName(first_dso_name)) { + Report("ASan runtime does not come first in initial library list; " + "you should either link runtime to your application or " + "manually preload it with LD_PRELOAD.\n"); + Die(); + } } } Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -316,6 +316,11 @@ // initialization steps look at flags(). InitializeFlags(); + CacheBinaryName(); + + AsanCheckIncompatibleRT(); + AsanCheckDynamicRTPrereqs(); + SetCanPoisonMemory(flags()->poison_heap); SetMallocContextSize(common_flags()->malloc_context_size); @@ -459,13 +464,11 @@ #if ASAN_DYNAMIC // Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable -// (and thus normal initializer from .preinit_array haven't run). +// (and thus normal initializers from .preinit_array or modules haven't run). class AsanInitializer { public: // NOLINT AsanInitializer() { - AsanCheckIncompatibleRT(); - AsanCheckDynamicRTPrereqs(); AsanInitFromRtl(); } }; @@ -517,7 +520,6 @@ // Initialize as requested from instrumented application code. // We use this call as a trigger to wake up ASan from deactivated state. void __asan_init() { - AsanCheckIncompatibleRT(); AsanActivate(); AsanInitInternal(); } Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -209,6 +209,10 @@ const char *StripModuleName(const char *module); // OS +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); +const char *GetBinaryName(); +const char *GetBinaryBasename(); +void CacheBinaryName(); void DisableCoreDumperIfNecessary(); void DumpProcessMap(); bool FileExists(const char *filename); Index: lib/sanitizer_common/sanitizer_common.cc =================================================================== --- lib/sanitizer_common/sanitizer_common.cc +++ lib/sanitizer_common/sanitizer_common.cc @@ -56,7 +56,14 @@ internal_close(fd); } - internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); + if (common_flags()->log_exe_name) { + const char *exe_name = GetBinaryBasename(); + internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, + exe_name, pid); + } else { + internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); + } + uptr openrv = OpenFile(full_path, true); if (internal_iserror(openrv)) { const char *ErrorMsgPrefix = "ERROR: Can't open file: "; @@ -220,6 +227,8 @@ return 0; if (const char *slash_pos = internal_strrchr(module, '/')) return slash_pos + 1; + else if (const char *backslash_pos = internal_strrchr(module, '\\')) + return backslash_pos + 1; return module; } @@ -334,6 +343,27 @@ return true; } +static char binary_name_cache_str[kMaxPathLength]; +static const char *binary_basename_cache_str = binary_name_cache_str; + +const char *GetBinaryName() { + return binary_name_cache_str; +} + +const char *GetBinaryBasename() { + return binary_basename_cache_str; +} + +// Call once to make sure that binary_name_cache_str is initialized +void CacheBinaryName() { + static bool binary_name_initialized; + if (LIKELY(binary_name_initialized)) + return; + ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); + binary_basename_cache_str = StripModuleName(binary_name_cache_str); + binary_name_initialized = true; +} + } // namespace __sanitizer using namespace __sanitizer; // NOLINT Index: lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- lib/sanitizer_common/sanitizer_flags.inc +++ lib/sanitizer_common/sanitizer_flags.inc @@ -51,6 +51,10 @@ "Write logs to \"log_path.pid\". The special values are \"stdout\" and " "\"stderr\". The default is \"stderr\".") COMMON_FLAG( + bool, log_exe_name, false, + "Mention name of executable when reporting error and " + "append executable name to logs (as in \"log_path.exe_name.pid\").") +COMMON_FLAG( int, verbosity, 0, "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.") Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -706,47 +706,32 @@ #endif } -static char proc_self_exe_cache_str[kMaxPathLength]; -static uptr proc_self_exe_cache_len = 0; - uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { - if (proc_self_exe_cache_len > 0) { - // If available, use the cached module name. - uptr module_name_len = - internal_snprintf(buf, buf_len, "%s", proc_self_exe_cache_str); - CHECK_LT(module_name_len, buf_len); - return module_name_len; - } #if SANITIZER_FREEBSD - const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + const int Mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + const char *default_module_name = "kern.proc.pathname"; size_t Size = buf_len; - bool IsErr = (sysctl(Mib, 4, buf, &Size, NULL, 0) != 0); + bool IsErr = (sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); int readlink_error = IsErr ? errno : 0; uptr module_name_len = Size; #else + const char *default_module_name = "/proc/self/exe"; uptr module_name_len = internal_readlink( - "/proc/self/exe", buf, buf_len); + default_module_name, buf, buf_len); int readlink_error; bool IsErr = internal_iserror(module_name_len, &readlink_error); #endif if (IsErr) { - // We can't read /proc/self/exe for some reason, assume the name of the - // binary is unknown. - Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, " + // We can't read binary name for some reason, assume it's unknown. + Report("WARNING: reading executable name failed with errno %d, " "some stack frames may not be symbolized\n", readlink_error); - module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe"); + module_name_len = internal_snprintf(buf, buf_len, "%s", + default_module_name); CHECK_LT(module_name_len, buf_len); } return module_name_len; } -void CacheBinaryName() { - if (!proc_self_exe_cache_len) { - proc_self_exe_cache_len = - ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength); - } -} - // Match full names of the form /path/to/base_name{-,.}* bool LibraryNameIs(const char *full_name, const char *base_name) { const char *name = full_name; Index: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -358,6 +358,13 @@ # endif // SANITIZER_WORDSIZE } +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + // FIXME: Actually implement this function. + CHECK_GT(buf_len, 0); + buf[0] = 0; + return 0; +} + } // namespace __sanitizer #endif // SANITIZER_MAC Index: lib/sanitizer_common/sanitizer_printf.cc =================================================================== --- lib/sanitizer_common/sanitizer_printf.cc +++ lib/sanitizer_common/sanitizer_printf.cc @@ -253,9 +253,16 @@ needed_length = 0; if (append_pid) { int pid = internal_getpid(); - needed_length += internal_snprintf(buffer, buffer_size, "==%d==", pid); + if (common_flags()->log_exe_name) { + const char *exe_name = GetBinaryBasename(); + needed_length += internal_snprintf(buffer, buffer_size, + "==%s", exe_name); + } + needed_length += internal_snprintf(buffer + needed_length, + buffer_size - needed_length, + "==%d==", pid); if (needed_length >= buffer_size) { - // The pid doesn't fit into the current buffer. + // Process name + pid do not fit into the current buffer. if (!use_mmap) continue; RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n"); Index: lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -358,12 +358,7 @@ return DemangleCXXABI(name); } - void PlatformPrepareForSandboxing() override { -#if SANITIZER_LINUX && !SANITIZER_ANDROID - // Cache /proc/self/exe on Linux. - CacheBinaryName(); -#endif - } + void PlatformPrepareForSandboxing() override {} LoadedModule *FindModuleForAddress(uptr address) { bool modules_were_reloaded = false; Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -648,6 +648,13 @@ return SignalContext(context, access_addr, pc, sp, bp); } +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + // FIXME: Actually implement this function. + CHECK_GT(buf_len, 0); + buf[0] = 0; + return 0; +} + } // namespace __sanitizer #endif // _WIN32 Index: lib/tsan/rtl/tsan_rtl.cc =================================================================== --- lib/tsan/rtl/tsan_rtl.cc +++ lib/tsan/rtl/tsan_rtl.cc @@ -306,6 +306,7 @@ if (is_initialized) return; is_initialized = true; + CacheBinaryName(); // We are not ready to handle interceptors yet. ScopedIgnoreInterceptors ignore; SanitizerToolName = "ThreadSanitizer"; Index: lib/ubsan/ubsan_init.cc =================================================================== --- lib/ubsan/ubsan_init.cc +++ lib/ubsan/ubsan_init.cc @@ -31,6 +31,7 @@ #endif if (LIKELY(ubsan_inited)) return; + CacheBinaryName(); bool standalone = false; if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) { // WARNING: If this condition holds, then either UBSan runs in a standalone Index: test/asan/TestCases/log-path_test.cc =================================================================== --- test/asan/TestCases/log-path_test.cc +++ test/asan/TestCases/log-path_test.cc @@ -29,16 +29,13 @@ // FIXME: log_path is not supported on Windows yet. // XFAIL: win32 -#include -#include +int glob[10]; + int main(int argc, char **argv) { if (argc > 2) return 0; - char *x = (char*)malloc(10); - memset(x, 0, 10); - int res = x[argc * 10]; // BOOOM - free(x); - return res; + return glob[argc * 10]; // BOOOM } + // CHECK-ERROR: ERROR: AddressSanitizer // CHECK-INVALID: ERROR: Can't open file: /dev/null/INVALID // CHECK-LONG: ERROR: Path is too long: 01234 Index: test/asan/TestCases/verbose-log-path_test.cc =================================================================== --- /dev/null +++ test/asan/TestCases/verbose-log-path_test.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_asan %s -o %t + +// Good log_path. +// RUN: rm -f %t.log.* +// RUN: env ASAN_OPTIONS=log_path=%t.log:log_exe_name=1 not %run %t 2> %t.out +// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.verbose-log-path_test.cc* + +// FIXME: only FreeBSD and Linux have verbose log paths now. +// XFAIL: win32 +// XFAIL: android +// XFAIL: darwin + +int glob[10]; + +int main(int argc, char **argv) { + return glob[argc * 10]; // BOOOM +} + +// CHECK-ERROR: ERROR: AddressSanitizer