forked from OSchip/llvm-project
Add AtosSymbolizer and DlAddrSymbolizer as fallbacks for OS X
This patch changes the symbolizer chain on OS X (which currently only uses 1 symbolizer at most) to use this behavior: * By default, use LLVMSymbolizer -> DlAddrSymbolizer. * If the llvm-symbolizer binary is not found, use AtosSymbolizer -> DlAddrSymbolizer. * If the user specifies ASAN_SYMBOLIZER_PATH=.../atos, then use AtosSymbolizer -> DlAddrSymbolizer. * If neither llvm-symbolizer or atos is found, or external symbolication is disabled with ASAN_SYMBOLIZER_PATH="", use DlAddrSymbolizer. Reviewed at http://reviews.llvm.org/D8285 llvm-svn: 232908
This commit is contained in:
parent
08dcf60295
commit
0be4e0e0c1
|
@ -23,6 +23,7 @@
|
|||
#include "sanitizer_procmaps.h"
|
||||
#include "sanitizer_symbolizer_internal.h"
|
||||
#include "sanitizer_symbolizer_libbacktrace.h"
|
||||
#include "sanitizer_symbolizer_mac.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -413,49 +414,87 @@ class POSIXSymbolizer : public Symbolizer {
|
|||
bool modules_fresh_;
|
||||
};
|
||||
|
||||
static SymbolizerTool *ChooseSymbolizer(LowLevelAllocator *allocator) {
|
||||
static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
|
||||
const char *path = common_flags()->external_symbolizer_path;
|
||||
const char *binary_name = path ? StripModuleName(path) : "";
|
||||
if (path && path[0] == '\0') {
|
||||
VReport(2, "External symbolizer is explicitly disabled.\n");
|
||||
return nullptr;
|
||||
} else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
|
||||
VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
|
||||
return new(*allocator) LLVMSymbolizer(path, allocator);
|
||||
} else if (!internal_strcmp(binary_name, "atos")) {
|
||||
#if SANITIZER_MAC
|
||||
VReport(2, "Using atos at user-specified path: %s\n", path);
|
||||
return new(*allocator) AtosSymbolizer(path, allocator);
|
||||
#else // SANITIZER_MAC
|
||||
Report("ERROR: Using `atos` is only supported on Darwin.\n");
|
||||
Die();
|
||||
#endif // SANITIZER_MAC
|
||||
} else if (!internal_strcmp(binary_name, "addr2line")) {
|
||||
VReport(2, "Using addr2line at user-specified path: %s\n", path);
|
||||
return new(*allocator) Addr2LinePool(path, allocator);
|
||||
} else if (path) {
|
||||
Report("ERROR: External symbolizer path is set to '%s' which isn't "
|
||||
"a known symbolizer. Please set the path to the llvm-symbolizer "
|
||||
"binary or other known tool.\n", path);
|
||||
Die();
|
||||
}
|
||||
|
||||
// Otherwise symbolizer program is unknown, let's search $PATH
|
||||
CHECK(path == nullptr);
|
||||
if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
|
||||
VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
|
||||
return new(*allocator) LLVMSymbolizer(found_path, allocator);
|
||||
}
|
||||
#if SANITIZER_MAC
|
||||
if (const char *found_path = FindPathToBinary("atos")) {
|
||||
VReport(2, "Using atos found at: %s\n", found_path);
|
||||
return new(*allocator) AtosSymbolizer(found_path, allocator);
|
||||
}
|
||||
#endif // SANITIZER_MAC
|
||||
if (common_flags()->allow_addr2line) {
|
||||
if (const char *found_path = FindPathToBinary("addr2line")) {
|
||||
VReport(2, "Using addr2line found at: %s\n", found_path);
|
||||
return new(*allocator) Addr2LinePool(found_path, allocator);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
|
||||
LowLevelAllocator *allocator) {
|
||||
if (!common_flags()->symbolize) {
|
||||
VReport(2, "Symbolizer is disabled.\n");
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
|
||||
VReport(2, "Using internal symbolizer.\n");
|
||||
return tool;
|
||||
list->push_back(tool);
|
||||
return;
|
||||
}
|
||||
if (SymbolizerTool *tool = LibbacktraceSymbolizer::get(allocator)) {
|
||||
VReport(2, "Using libbacktrace symbolizer.\n");
|
||||
return tool;
|
||||
list->push_back(tool);
|
||||
return;
|
||||
}
|
||||
const char *path_to_external = common_flags()->external_symbolizer_path;
|
||||
if (path_to_external && path_to_external[0] == '\0') {
|
||||
// External symbolizer is explicitly disabled. Do nothing.
|
||||
return nullptr;
|
||||
|
||||
if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) {
|
||||
list->push_back(tool);
|
||||
} else {
|
||||
VReport(2, "No internal or external symbolizer found.\n");
|
||||
}
|
||||
// Find path to llvm-symbolizer if it's not provided.
|
||||
if (!path_to_external) {
|
||||
path_to_external = FindPathToBinary("llvm-symbolizer");
|
||||
}
|
||||
if (path_to_external) {
|
||||
VReport(2, "Using llvm-symbolizer at path: %s\n", path_to_external);
|
||||
return new(*allocator) LLVMSymbolizer(path_to_external, allocator);
|
||||
}
|
||||
if (common_flags()->allow_addr2line) {
|
||||
// If llvm-symbolizer is not found, try to use addr2line.
|
||||
if (const char *addr2line_path = FindPathToBinary("addr2line")) {
|
||||
VReport(2, "Using addr2line at path: %s\n", addr2line_path);
|
||||
return new(*allocator) Addr2LinePool(addr2line_path, allocator);
|
||||
}
|
||||
}
|
||||
VReport(2, "No internal or external symbolizer found.\n");
|
||||
return nullptr;
|
||||
|
||||
#if SANITIZER_MAC
|
||||
VReport(2, "Using dladdr symbolizer.\n");
|
||||
list->push_back(new(*allocator) DlAddrSymbolizer());
|
||||
#endif // SANITIZER_MAC
|
||||
}
|
||||
|
||||
Symbolizer *Symbolizer::PlatformInit() {
|
||||
IntrusiveList<SymbolizerTool> list;
|
||||
list.clear();
|
||||
if (SymbolizerTool *tool = ChooseSymbolizer(&symbolizer_allocator_)) {
|
||||
list.push_back(tool);
|
||||
}
|
||||
ChooseSymbolizerTools(&list, &symbolizer_allocator_);
|
||||
return new(symbolizer_allocator_) POSIXSymbolizer(list);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Check that the `atos` symbolizer works.
|
||||
|
||||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: ASAN_OPTIONS=verbosity=2 ASAN_SYMBOLIZER_PATH=$(which atos) not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// Check that when having a DYLD_ROOT_PATH set, the symbolizer still works.
|
||||
// RUN: DYLD_ROOT_PATH="/" ASAN_OPTIONS=verbosity=2 ASAN_SYMBOLIZER_PATH=$(which atos) \
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
int main(int argc, char **argv) {
|
||||
char *x = (char*)malloc(10 * sizeof(char));
|
||||
memset(x, 0, 10);
|
||||
int res = x[argc];
|
||||
free(x);
|
||||
free(x + argc - 1); // BOOM
|
||||
// CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
|
||||
// CHECK: Using atos at user-specified path:
|
||||
// CHECK: #0 0x{{.*}} in {{.*}}free
|
||||
// CHECK: #1 0x{{.*}} in main {{.*}}atos-symbolizer.cc:[[@LINE-4]]
|
||||
// CHECK: freed by thread T0 here:
|
||||
// CHECK: #0 0x{{.*}} in {{.*}}free
|
||||
// CHECK: #1 0x{{.*}} in main {{.*}}atos-symbolizer.cc:[[@LINE-8]]
|
||||
// CHECK: allocated by thread T0 here:
|
||||
// CHECK: atos-symbolizer.cc:[[@LINE-13]]
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// In a non-forking sandbox, we can't spawn an external symbolizer, but dladdr()
|
||||
// should still work and provide function names. No line numbers though.
|
||||
// Second, `atos` symbolizer can't inspect a process that has an inaccessible
|
||||
// task port, in which case we should again fallback to dladdr gracefully.
|
||||
|
||||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny process-fork)' %t 2>&1 | FileCheck %s
|
||||
// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s
|
||||
// RUN: ASAN_SYMBOLIZER_PATH="" not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx_asan -O3 %s -o %t
|
||||
// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny process-fork)' %t 2>&1 | FileCheck %s
|
||||
// RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s
|
||||
// RUN: ASAN_SYMBOLIZER_PATH="" not %run sandbox-exec -p '(version 1)(allow default)(deny mach-priv-task-port)' %t 2>&1 | FileCheck %s
|
||||
|
||||
#include <stdlib.h>
|
||||
int main() {
|
||||
char *x = (char*)malloc(10 * sizeof(char));
|
||||
free(x);
|
||||
return x[5];
|
||||
// CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
|
||||
// CHECK: {{READ of size 1 at 0x.* thread T0}}
|
||||
// CHECK: {{ #0 0x.* in main}}
|
||||
// CHECK: {{freed by thread T0 here:}}
|
||||
// CHECK: {{ #0 0x.* in wrap_free}}
|
||||
// CHECK: {{ #1 0x.* in main}}
|
||||
// CHECK: {{previously allocated by thread T0 here:}}
|
||||
// CHECK: {{ #0 0x.* in wrap_malloc}}
|
||||
// CHECK: {{ #1 0x.* in main}}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Check that without suppressions, we catch the issue.
|
||||
// RUN: %clangxx_asan -O0 %s -o %t -framework Foundation
|
||||
// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
|
||||
|
||||
// Check that suppressing a function name works within a no-fork sandbox
|
||||
// RUN: echo "interceptor_via_fun:CFStringCreateWithBytes" > %t.supp
|
||||
// RUN: ASAN_OPTIONS=suppressions=%t.supp \
|
||||
// RUN: sandbox-exec -p '(version 1)(allow default)(deny process-fork)' \
|
||||
// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
int main() {
|
||||
char *a = (char *)malloc(6);
|
||||
strcpy(a, "hello");
|
||||
CFStringRef str =
|
||||
CFStringCreateWithBytes(kCFAllocatorDefault, (unsigned char *)a, 10,
|
||||
kCFStringEncodingUTF8, FALSE); // BOOM
|
||||
fprintf(stderr, "Ignored.\n");
|
||||
free(a);
|
||||
}
|
||||
|
||||
// CHECK-CRASH: AddressSanitizer: heap-buffer-overflow
|
||||
// CHECK-CRASH-NOT: Ignored.
|
||||
// CHECK-IGNORE-NOT: AddressSanitizer: heap-buffer-overflow
|
||||
// CHECK-IGNORE: Ignored.
|
Loading…
Reference in New Issue