Skip to content

Commit

Permalink
[asan] Add %d variable to external_symbolizer_path option, so that us…
Browse files Browse the repository at this point in the history
…er can specify paths relative to the location of the binary.

We want way to set a path to llvm-symbolizer that isn't relative
to the current working directory; this change adds a variable that
expands to the path relative to the current binary.
This approach came from comments in https://reviews.llvm.org/D93070

Differential Revision: https://reviews.llvm.org/D94563
  • Loading branch information
amykhuang committed Feb 4, 2021
1 parent e21adfa commit 9ba623c
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 8 deletions.
8 changes: 8 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
Expand Up @@ -274,6 +274,14 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
return name_len;
}

uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
ReadBinaryNameCached(buf, buf_len);
const char *exec_name_pos = StripModuleName(buf);
uptr name_len = exec_name_pos - buf;
buf[name_len] = '\0';
return name_len;
}

#if !SANITIZER_GO
void PrintCmdline() {
char **argv = GetArgv();
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common.h
Expand Up @@ -248,6 +248,7 @@ const char *StripModuleName(const char *module);
// OS
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len);
uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
const char *GetProcessName();
void UpdateProcessName();
Expand Down
7 changes: 7 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp
Expand Up @@ -35,6 +35,7 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
// Copy the string from "s" to "out", making the following substitutions:
// %b = binary basename
// %p = pid
// %d = binary directory
void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
char *out_end = out + out_size;
while (*s && out < out_end - 1) {
Expand Down Expand Up @@ -64,6 +65,12 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
s += 2; // skip "%p"
break;
}
case 'd': {
uptr len = ReadBinaryDir(out, out_end - out);
out += len;
s += 2; // skip "%d"
break;
}
default:
*out++ = *s++;
break;
Expand Down
Expand Up @@ -400,6 +400,13 @@ const char *Symbolizer::PlatformDemangle(const char *name) {

static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
const char *path = common_flags()->external_symbolizer_path;

if (path && internal_strchr(path, '%')) {
char *new_path = (char *)InternalAlloc(kMaxPathLength);
SubstituteForFlagValue(path, new_path, kMaxPathLength);
path = new_path;
}

const char *binary_name = path ? StripModuleName(path) : "";
if (path && path[0] == '\0') {
VReport(2, "External symbolizer is explicitly disabled.\n");
Expand Down
Expand Up @@ -288,8 +288,15 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
return;
}

// Add llvm-symbolizer in case the binary has dwarf.
// Add llvm-symbolizer.
const char *user_path = common_flags()->external_symbolizer_path;

if (user_path && internal_strchr(user_path, '%')) {
char *new_path = (char *)InternalAlloc(kMaxPathLength);
SubstituteForFlagValue(user_path, new_path, kMaxPathLength);
user_path = new_path;
}

const char *path =
user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
if (path) {
Expand Down
21 changes: 17 additions & 4 deletions compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
Expand Up @@ -1049,10 +1049,23 @@ const char *SignalContext::Describe() const {
}

uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
// FIXME: Actually implement this function.
CHECK_GT(buf_len, 0);
buf[0] = 0;
return 0;
if (buf_len == 0)
return 0;

// Get the UTF-16 path and convert to UTF-8.
wchar_t binname_utf16[kMaxPathLength];
int binname_utf16_len =
GetModuleFileNameW(NULL, binname_utf16, ARRAY_SIZE(binname_utf16));
if (binname_utf16_len == 0) {
buf[0] = '\0';
return 0;
}
int binary_name_len = ::WideCharToMultiByte(
CP_UTF8, 0, binname_utf16, binname_utf16_len, buf, buf_len, NULL, NULL);
if ((unsigned)binary_name_len == buf_len)
--binary_name_len;
buf[binary_name_len] = '\0';
return binary_name_len;
}

uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
Expand Down
Expand Up @@ -461,12 +461,9 @@ TEST(SanitizerCommon, ReservedAddressRangeUnmap) {
EXPECT_DEATH(address_range.Unmap(base_addr + (PageSize * 2), PageSize), ".*");
}

// Windows has no working ReadBinaryName.
#if !SANITIZER_WINDOWS
TEST(SanitizerCommon, ReadBinaryNameCached) {
char buf[256];
EXPECT_NE((uptr)0, ReadBinaryNameCached(buf, sizeof(buf)));
}
#endif

} // namespace __sanitizer
@@ -0,0 +1,30 @@
// REQUIRES: shell
// RUN: rm -rf %t.bin
// RUN: mkdir %t.bin
// RUN: cp $(which llvm-symbolizer) %t.bin
// RUN: rm -rf %t.dir
// RUN: mkdir %t.dir
// RUN: %clangxx -O0 %s -o %t && cd %t.dir
// RUN: %env_tool_opts=external_symbolizer_path=%d/external_symbolizer_path.cpp.tmp.bin/llvm-symbolizer \
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=FOUND
// RUN: rm -rf %t.bin/llvm-symbolizer
// RUN: cd ..
// RUN: %clangxx -O0 %s -o %t && cd %t.dir
// RUN: %env_tool_opts=external_symbolizer_path=%d/external_symbolizer_path.cpp.tmp.bin/llvm-symbolizer \
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=NOT-FOUND

#include <sanitizer/common_interface_defs.h>
#include <stdio.h>

static void Symbolize() {
char buffer[100];
__sanitizer_symbolize_pc(__builtin_return_address(0), "%p %F %L", buffer,
sizeof(buffer));
printf("%s\n", buffer);
}

int main() {
// FOUND: {{0x.* in main}}
// NOT-FOUND: WARNING: invalid path to external symbolizer!
Symbolize();
}

0 comments on commit 9ba623c

Please sign in to comment.