summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2012-09-14 04:35:14 +0000
committerKostya Serebryany <kcc@google.com>2012-09-14 04:35:14 +0000
commit81dfbb76f858fbc4084771fce4967ede04ed5f44 (patch)
treeabb184ff829cf56b9ce130f5b22ee1cf9a0faf21 /lib
parent484db99999ebadcc62bd5ac5a702d1fdad391111 (diff)
[asan] add asan option log_path=PATH to let users redirect asan reports to a file PATH.PID instead of stderr
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@163872 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/asan/asan_flags.h2
-rw-r--r--lib/asan/asan_rtl.cc3
-rw-r--r--lib/asan/lit_tests/log-path_test.cc39
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc30
-rw-r--r--lib/sanitizer_common/sanitizer_printf.cc7
5 files changed, 78 insertions, 3 deletions
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index de7475bc1..989784df0 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -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();
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 41fbe6a44..97cb061d8 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -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);
diff --git a/lib/asan/lit_tests/log-path_test.cc b/lib/asan/lit_tests/log-path_test.cc
new file mode 100644
index 000000000..1072670fb
--- /dev/null
+++ b/lib/asan/lit_tests/log-path_test.cc
@@ -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
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 22c7093db..614b7b9d4 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -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;
+}
diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc
index 22f10fb1a..6aeedabdf 100644
--- a/lib/sanitizer_common/sanitizer_printf.cc
+++ b/lib/sanitizer_common/sanitizer_printf.cc
@@ -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, '%');