Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -214,6 +214,11 @@ bool SetEnv(const char *name, const char *value); const char *GetPwd(); char *FindPathToBinary(const char *name); +bool IsPathSeparator(const char c); +bool IsAbsolutePath(const char *path); + +// Returns the path to the main executable. +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); u32 GetUid(); void ReExec(); bool StackSizeIsUnlimited(); Index: lib/sanitizer_common/sanitizer_linux.h =================================================================== --- lib/sanitizer_common/sanitizer_linux.h +++ lib/sanitizer_common/sanitizer_linux.h @@ -80,8 +80,6 @@ // information). bool LibraryNameIs(const char *full_name, const char *base_name); -// Read the name of the current binary from /proc/self/exe. -uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); // Cache the value of /proc/self/exe. void CacheBinaryName(); Index: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -31,9 +31,11 @@ #include // for _NSGetEnviron #include +#include #include #include #include +#include #include #include #include @@ -204,6 +206,20 @@ return 0; } +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + CHECK_LE(kMaxPathLength, buf_len); + + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + InternalScopedString exe_path(kMaxPathLength); + uint32_t size = exe_path.size(); + if (_NSGetExecutablePath(exe_path.data(), &size) == 0) + if (realpath(exe_path.data(), buf) != 0) + return internal_strlen(buf); + return 0; +} + void ReExec() { UNIMPLEMENTED(); } Index: lib/sanitizer_common/sanitizer_posix.cc =================================================================== --- lib/sanitizer_common/sanitizer_posix.cc +++ lib/sanitizer_common/sanitizer_posix.cc @@ -293,6 +293,14 @@ return 0; } +bool IsPathSeparator(const char c) { + return c == '/'; +} + +bool IsAbsolutePath(const char *path) { + return IsPathSeparator(path[0]); +} + void ReportFile::Write(const char *buffer, uptr length) { SpinMutexLock l(mu); static const char *kWriteError = Index: lib/sanitizer_common/sanitizer_suppressions.cc =================================================================== --- lib/sanitizer_common/sanitizer_suppressions.cc +++ lib/sanitizer_common/sanitizer_suppressions.cc @@ -80,17 +80,47 @@ return suppression_ctx; } +static bool GetPathRelativeToExec(const char *file_path, + /*out*/char *rel_file_path) { + InternalScopedString exec(kMaxPathLength); + if (ReadBinaryName(exec.data(), exec.size())) { + const char *file_name_pos = StripModuleName(exec.data()); + uptr path_to_exec_len = file_name_pos - exec.data(); + internal_memcpy(rel_file_path, exec.data(), path_to_exec_len); + internal_memcpy(rel_file_path + path_to_exec_len, + file_path, + internal_strlen(file_path) + 1); + return true; + } + return false; +} + void SuppressionContext::InitIfNecessary() { if (suppression_ctx) return; suppression_ctx = new(placeholder) SuppressionContext; if (common_flags()->suppressions[0] == '\0') return; + + const char *file_path = common_flags()->suppressions; char *suppressions_from_file; uptr buffer_size; + uptr max_len = 1 << 26; + + // If we cannot find the file, check if its location is relative to + // the location of the executable. + InternalScopedString new_file_path(kMaxPathLength); + if (!FileExists(file_path) && !IsAbsolutePath(file_path) && + GetPathRelativeToExec(file_path, new_file_path.data())) { + file_path = new_file_path.data(); + } + uptr contents_size = - ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file, - &buffer_size, 1 << 26 /* max_len */); + ReadFileToBuffer(file_path, &suppressions_from_file, &buffer_size, max_len); + + VPrintf(1, "%s: reading suppressions file at %s\n", + SanitizerToolName, file_path); + if (contents_size == 0) { Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, common_flags()->suppressions); Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -311,6 +311,19 @@ return 0; } +uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + // Nothing here for now. + return 0; +} + +bool IsPathSeparator(const char c) { + UNIMPLEMENTED(); +} + +bool IsAbsolutePath(const char *path) { + UNIMPLEMENTED(); +} + void SleepForSeconds(int seconds) { Sleep(seconds * 1000); } Index: test/asan/TestCases/suppressions-exec-relative-location.cc =================================================================== --- /dev/null +++ test/asan/TestCases/suppressions-exec-relative-location.cc @@ -0,0 +1,47 @@ +// Check that without suppressions, we catch the issue. +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s + +// If the executable is started from a different location, we should still +// find the suppression file located relative to the location of the executable. +// RUN: rm -rf %T/suppressions-exec-relative-location +// RUN: mkdir -p %T/suppressions-exec-relative-location +// RUN: %clangxx_asan -O0 %s -o %T/suppressions-exec-relative-location/exec +// RUN: echo "interceptor_via_fun:crash_function" > \ +// RUN: %T/suppressions-exec-relative-location/supp.txt +// RUN: ASAN_OPTIONS="suppressions=supp.txt" \ +// RUN: %run %T/suppressions-exec-relative-location/exec 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: rm -rf %T/suppressions-exec-relative-location + +// If the wrong absolute path is given, we don't try to construct +// a relative path with it. +// RUN: ASAN_OPTIONS="suppressions='/absolute/path'" not %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-WRONG-FILE-NAME %s + +// Test that we reject directory as filename. +// RUN: ASAN_OPTIONS="suppressions='folder/only/'" not %run %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-WRONG-FILE-NAME %s + +// XFAIL: android +// XFAIL: win32 + +#include +#include +#include + +void crash_function() { + char *a = (char *)malloc(6); + free(a); + size_t len = strlen(a); // BOOM + fprintf(stderr, "strlen ignored, len = %zu\n", len); +} + +int main() { + crash_function(); +} + +// CHECK-CRASH: AddressSanitizer: heap-use-after-free +// CHECK-IGNORE-NOT: AddressSanitizer: heap-buffer-overflow +// CHECK-IGNORE: ignored +// CHECK-WRONG-FILE-NAME: failed to read suppressions file