[compiler-rt] Allow suppression file to be relative to the location of the executable

The ASanified executable could be launched from different locations. When we
cannot find the suppression file relative to the current directory, try to
see if the specified path is relative to the location of the executable.

llvm-svn: 230723
This commit is contained in:
Anna Zaks 2015-02-27 03:12:19 +00:00
parent 5bc883f39e
commit 2249049db2
7 changed files with 124 additions and 4 deletions

View File

@ -216,6 +216,11 @@ const char *GetEnv(const char *name);
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();

View File

@ -80,8 +80,6 @@ uptr ThreadSelfOffset();
// 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();

View File

@ -31,9 +31,11 @@
#include <crt_externs.h> // for _NSGetEnviron
#include <fcntl.h>
#include <mach-o/dyld.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
@ -204,6 +206,21 @@ const char *GetEnv(const char *name) {
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 &&
realpath(exe_path.data(), buf) != 0) {
return internal_strlen(buf);
}
return 0;
}
void ReExec() {
UNIMPLEMENTED();
}

View File

@ -293,6 +293,14 @@ char *FindPathToBinary(const char *name) {
return 0;
}
bool IsPathSeparator(const char c) {
return c == '/';
}
bool IsAbsolutePath(const char *path) {
return path != nullptr && IsPathSeparator(path[0]);
}
void ReportFile::Write(const char *buffer, uptr length) {
SpinMutexLock l(mu);
static const char *kWriteError =

View File

@ -30,18 +30,50 @@ SuppressionContext::SuppressionContext(const char *suppression_types[],
internal_memset(has_suppression_type_, 0, suppression_types_num_);
}
static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
/*out*/char *new_file_path,
uptr new_file_path_size) {
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_strncat(new_file_path, exec.data(),
Min(path_to_exec_len, new_file_path_size - 1));
internal_strncat(new_file_path, file_path,
new_file_path_size - internal_strlen(new_file_path) - 1);
return true;
}
return false;
}
void SuppressionContext::ParseFromFile(const char *filename) {
if (filename[0] == '\0')
return;
// 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(filename) && !IsAbsolutePath(filename) &&
GetPathAssumingFileIsRelativeToExec(filename, new_file_path.data(),
new_file_path.size())) {
filename = new_file_path.data();
}
// Read the file.
char *file_contents;
uptr buffer_size;
uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size,
1 << 26 /* max_len */);
const uptr max_len = 1 << 26;
uptr contents_size =
ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len);
VPrintf(1, "%s: reading suppressions file at %s\n",
SanitizerToolName, filename);
if (contents_size == 0) {
Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
filename);
Die();
}
Parse(file_contents);
}

View File

@ -313,6 +313,19 @@ char *FindPathToBinary(const char *name) {
return 0;
}
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
// Nothing here for now.
return 0;
}
bool IsPathSeparator(const char c) {
return c == '\\' || c == '/';
}
bool IsAbsolutePath(const char *path) {
UNIMPLEMENTED();
}
void SleepForSeconds(int seconds) {
Sleep(seconds * 1000);
}

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
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