[asan] add asan option log_path=PATH to let users redirect asan reports to a file PATH.PID instead of stderr

llvm-svn: 163872
This commit is contained in:
Kostya Serebryany 2012-09-14 04:35:14 +00:00
parent 6d149412c8
commit 45d849c4bd
6 changed files with 84 additions and 3 deletions

View File

@ -53,4 +53,10 @@ typedef signed long long s64; // NOLINT
} // namespace __sanitizer
extern "C" {
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
void __sanitizer_set_report_path(const char *path)
SANITIZER_INTERFACE_ATTRIBUTE;
} // extern "C"
#endif // SANITIZER_COMMON_INTERFACE_DEFS_H

View File

@ -93,6 +93,8 @@ struct Flags {
// but also thread creation stacks for threads that created those threads,
// etc. up to main thread.
bool print_full_thread_history;
// ASan will write logs to "log_path.pid" instead of stderr.
const char *log_path;
};
Flags *flags();

View File

@ -99,6 +99,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
ParseFlag(str, &f->allow_reexec, "allow_reexec");
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
ParseFlag(str, &f->log_path, "log_path");
}
extern "C" {
@ -137,6 +138,7 @@ void InitializeFlags(Flags *f, const char *env) {
f->strip_path_prefix = "";
f->allow_reexec = true;
f->print_full_thread_history = true;
f->log_path = 0;
// Override from user-specified string.
ParseFlagsFromString(f, __asan_default_options());
@ -295,6 +297,7 @@ void __asan_init() {
// initialization steps look at flags().
const char *options = GetEnv("ASAN_OPTIONS");
InitializeFlags(flags(), options);
__sanitizer_set_report_path(flags()->log_path);
if (flags()->verbosity && options) {
Report("Parsed ASAN_OPTIONS: %s\n", options);

View File

@ -0,0 +1,39 @@
// RUN: %clangxx_asan %s -o %t
// Regular run.
// RUN: not %t 2> %t.out
// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.out
// Good log_path.
// RUN: rm -f %t.log.*
// RUN: ASAN_OPTIONS=log_path=%t.log not %t 2> %t.out
// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.*
// Invalid log_path.
// RUN: ASAN_OPTIONS=log_path=/INVALID not %t 2> %t.out
// RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out
// Too long log_path.
// RUN: ASAN_OPTIONS=log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \
// RUN: not %t 2> %t.out
// RUN: FileCheck %s --check-prefix=CHECK-LONG < %t.out
// Run w/o errors should not produce any log.
// RUN: rm -f %t.log.*
// RUN: ASAN_OPTIONS=log_path=%t.log %t ARG ARG ARG
// RUN: not cat %t.log.*
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc > 2) return 0;
char *x = (char*)malloc(10);
memset(x, 0, 10);
int res = x[argc * 10]; // BOOOM
free(x);
return res;
}
// CHECK-ERROR: ERROR: AddressSanitizer
// CHECK-INVALID: ERROR: Can't open file: /INVALID
// CHECK-LONG: ERROR: Path is too long: 01234

View File

@ -16,6 +16,9 @@
namespace __sanitizer {
static fd_t report_fd = 2; // By default, dump to stderr.
static char report_path[4096]; // Set via __sanitizer_set_report_path.
static void (*DieCallback)(void);
void SetDieCallback(void (*callback)(void)) {
DieCallback = callback;
@ -46,8 +49,17 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
void RawWrite(const char *buffer) {
static const char *kRawWriteError = "RawWrite can't output requested buffer!";
uptr length = (uptr)internal_strlen(buffer);
if (length != internal_write(2, buffer, length)) {
internal_write(2, kRawWriteError, internal_strlen(kRawWriteError));
if (report_fd == kInvalidFd) {
fd_t fd = internal_open(report_path, true);
if (fd == kInvalidFd) {
report_fd = 2;
Report("ERROR: Can't open file: %s\n", report_path);
Die();
}
report_fd = fd;
}
if (length != internal_write(report_fd, buffer, length)) {
internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
Die();
}
}
@ -125,3 +137,17 @@ void SortArray(uptr *array, uptr size) {
}
} // namespace __sanitizer
void __sanitizer_set_report_path(const char *path) {
if (!path) return;
uptr len = internal_strlen(path);
if (len > sizeof(__sanitizer::report_path) - 100) {
Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
path[0], path[1], path[2], path[3],
path[4], path[5], path[6], path[7]);
Die();
}
internal_snprintf(__sanitizer::report_path,
sizeof(__sanitizer::report_path), "%s.%d", path, GetPid());
__sanitizer::report_fd = kInvalidFd;
}

View File

@ -86,7 +86,7 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
int VSNPrintf(char *buff, int buff_length,
const char *format, va_list args) {
static const char *kPrintfFormatsHelp = "Supported Printf formats: "
"%%[z]{d,u,x}; %%p; %%s\n";
"%%[z]{d,u,x}; %%p; %%s; %%c\n";
RAW_CHECK(format);
RAW_CHECK(buff_length > 0);
const char *buff_end = &buff[buff_length - 1];
@ -127,6 +127,11 @@ int VSNPrintf(char *buff, int buff_length,
result += AppendString(&buff, buff_end, va_arg(args, char*));
break;
}
case 'c': {
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
result += AppendChar(&buff, buff_end, va_arg(args, uptr));
break;
}
case '%' : {
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
result += AppendChar(&buff, buff_end, '%');