Skip to content

Commit 2249049

Browse files
committed
[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
1 parent 5bc883f commit 2249049

File tree

7 files changed

+124
-4
lines changed

7 files changed

+124
-4
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ const char *GetEnv(const char *name);
216216
bool SetEnv(const char *name, const char *value);
217217
const char *GetPwd();
218218
char *FindPathToBinary(const char *name);
219+
bool IsPathSeparator(const char c);
220+
bool IsAbsolutePath(const char *path);
221+
222+
// Returns the path to the main executable.
223+
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
219224
u32 GetUid();
220225
void ReExec();
221226
bool StackSizeIsUnlimited();

compiler-rt/lib/sanitizer_common/sanitizer_linux.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ uptr ThreadSelfOffset();
8080
// information).
8181
bool LibraryNameIs(const char *full_name, const char *base_name);
8282

83-
// Read the name of the current binary from /proc/self/exe.
84-
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
8583
// Cache the value of /proc/self/exe.
8684
void CacheBinaryName();
8785

compiler-rt/lib/sanitizer_common/sanitizer_mac.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131

3232
#include <crt_externs.h> // for _NSGetEnviron
3333
#include <fcntl.h>
34+
#include <mach-o/dyld.h>
3435
#include <pthread.h>
3536
#include <sched.h>
3637
#include <signal.h>
38+
#include <stdlib.h>
3739
#include <sys/mman.h>
3840
#include <sys/resource.h>
3941
#include <sys/stat.h>
@@ -204,6 +206,21 @@ const char *GetEnv(const char *name) {
204206
return 0;
205207
}
206208

209+
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
210+
CHECK_LE(kMaxPathLength, buf_len);
211+
212+
// On OS X the executable path is saved to the stack by dyld. Reading it
213+
// from there is much faster than calling dladdr, especially for large
214+
// binaries with symbols.
215+
InternalScopedString exe_path(kMaxPathLength);
216+
uint32_t size = exe_path.size();
217+
if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
218+
realpath(exe_path.data(), buf) != 0) {
219+
return internal_strlen(buf);
220+
}
221+
return 0;
222+
}
223+
207224
void ReExec() {
208225
UNIMPLEMENTED();
209226
}

compiler-rt/lib/sanitizer_common/sanitizer_posix.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ char *FindPathToBinary(const char *name) {
293293
return 0;
294294
}
295295

296+
bool IsPathSeparator(const char c) {
297+
return c == '/';
298+
}
299+
300+
bool IsAbsolutePath(const char *path) {
301+
return path != nullptr && IsPathSeparator(path[0]);
302+
}
303+
296304
void ReportFile::Write(const char *buffer, uptr length) {
297305
SpinMutexLock l(mu);
298306
static const char *kWriteError =

compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,50 @@ SuppressionContext::SuppressionContext(const char *suppression_types[],
3030
internal_memset(has_suppression_type_, 0, suppression_types_num_);
3131
}
3232

33+
static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
34+
/*out*/char *new_file_path,
35+
uptr new_file_path_size) {
36+
InternalScopedString exec(kMaxPathLength);
37+
if (ReadBinaryName(exec.data(), exec.size())) {
38+
const char *file_name_pos = StripModuleName(exec.data());
39+
uptr path_to_exec_len = file_name_pos - exec.data();
40+
internal_strncat(new_file_path, exec.data(),
41+
Min(path_to_exec_len, new_file_path_size - 1));
42+
internal_strncat(new_file_path, file_path,
43+
new_file_path_size - internal_strlen(new_file_path) - 1);
44+
return true;
45+
}
46+
return false;
47+
}
48+
3349
void SuppressionContext::ParseFromFile(const char *filename) {
3450
if (filename[0] == '\0')
3551
return;
52+
53+
// If we cannot find the file, check if its location is relative to
54+
// the location of the executable.
55+
InternalScopedString new_file_path(kMaxPathLength);
56+
if (!FileExists(filename) && !IsAbsolutePath(filename) &&
57+
GetPathAssumingFileIsRelativeToExec(filename, new_file_path.data(),
58+
new_file_path.size())) {
59+
filename = new_file_path.data();
60+
}
61+
62+
// Read the file.
3663
char *file_contents;
3764
uptr buffer_size;
38-
uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size,
39-
1 << 26 /* max_len */);
65+
const uptr max_len = 1 << 26;
66+
uptr contents_size =
67+
ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len);
68+
VPrintf(1, "%s: reading suppressions file at %s\n",
69+
SanitizerToolName, filename);
70+
4071
if (contents_size == 0) {
4172
Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
4273
filename);
4374
Die();
4475
}
76+
4577
Parse(file_contents);
4678
}
4779

compiler-rt/lib/sanitizer_common/sanitizer_win.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,19 @@ char *FindPathToBinary(const char *name) {
313313
return 0;
314314
}
315315

316+
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
317+
// Nothing here for now.
318+
return 0;
319+
}
320+
321+
bool IsPathSeparator(const char c) {
322+
return c == '\\' || c == '/';
323+
}
324+
325+
bool IsAbsolutePath(const char *path) {
326+
UNIMPLEMENTED();
327+
}
328+
316329
void SleepForSeconds(int seconds) {
317330
Sleep(seconds * 1000);
318331
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Check that without suppressions, we catch the issue.
2+
// RUN: %clangxx_asan -O0 %s -o %t
3+
// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
4+
5+
// If the executable is started from a different location, we should still
6+
// find the suppression file located relative to the location of the executable.
7+
// RUN: rm -rf %T/suppressions-exec-relative-location
8+
// RUN: mkdir -p %T/suppressions-exec-relative-location
9+
// RUN: %clangxx_asan -O0 %s -o %T/suppressions-exec-relative-location/exec
10+
// RUN: echo "interceptor_via_fun:crash_function" > \
11+
// RUN: %T/suppressions-exec-relative-location/supp.txt
12+
// RUN: ASAN_OPTIONS="suppressions=supp.txt" \
13+
// RUN: %run %T/suppressions-exec-relative-location/exec 2>&1 | \
14+
// RUN: FileCheck --check-prefix=CHECK-IGNORE %s
15+
// RUN: rm -rf %T/suppressions-exec-relative-location
16+
17+
// If the wrong absolute path is given, we don't try to construct
18+
// a relative path with it.
19+
// RUN: ASAN_OPTIONS="suppressions='/absolute/path'" not %run %t 2>&1 | \
20+
// RUN: FileCheck --check-prefix=CHECK-WRONG-FILE-NAME %s
21+
22+
// Test that we reject directory as filename.
23+
// RUN: ASAN_OPTIONS="suppressions='folder/only/'" not %run %t 2>&1 | \
24+
// RUN: FileCheck --check-prefix=CHECK-WRONG-FILE-NAME %s
25+
26+
// XFAIL: android
27+
// XFAIL: win32
28+
29+
#include <stdio.h>
30+
#include <stdlib.h>
31+
#include <string.h>
32+
33+
void crash_function() {
34+
char *a = (char *)malloc(6);
35+
free(a);
36+
size_t len = strlen(a); // BOOM
37+
fprintf(stderr, "strlen ignored, len = %zu\n", len);
38+
}
39+
40+
int main() {
41+
crash_function();
42+
}
43+
44+
// CHECK-CRASH: AddressSanitizer: heap-use-after-free
45+
// CHECK-IGNORE-NOT: AddressSanitizer: heap-buffer-overflow
46+
// CHECK-IGNORE: ignored
47+
// CHECK-WRONG-FILE-NAME: failed to read suppressions file

0 commit comments

Comments
 (0)