From d483c072af66dced0624b9ac2fa03b27f8dcd750 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 5 Sep 2013 03:19:57 +0000 Subject: [PATCH] sanitizers: Make sure Visual Studio gets error reports Visual Studio appears to close stderr before launching a non-console win32 program. This means we don't see any sanitizer reports. If stderr printing fails, call OutputDebugStringA to get the reports into the Visual Studio debugger console. llvm-svn: 190030 --- .../lib/sanitizer_common/sanitizer_common.cc | 39 +++---------------- .../lib/sanitizer_common/sanitizer_common.h | 3 ++ .../lib/sanitizer_common/sanitizer_posix.cc | 31 +++++++++++++++ .../lib/sanitizer_common/sanitizer_win.cc | 18 +++++++++ 4 files changed, 58 insertions(+), 33 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc index bb601bd6aa23..4aab65d914b2 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc @@ -26,16 +26,19 @@ uptr GetPageSizeCached() { return PageSize; } -static bool log_to_file = false; // Set to true by __sanitizer_set_report_path // By default, dump to stderr. If |log_to_file| is true and |report_fd_pid| // isn't equal to the current PID, try to obtain file descriptor by opening // file "report_path_prefix.". fd_t report_fd = kStderrFd; -static char report_path_prefix[4096]; // Set via __sanitizer_set_report_path. + +// Set via __sanitizer_set_report_path. +bool log_to_file = false; +char report_path_prefix[sizeof(report_path_prefix)]; + // PID of process that opened |report_fd|. If a fork() occurs, the PID of the // child thread will be different from |report_fd_pid|. -static uptr report_fd_pid = 0; +uptr report_fd_pid = 0; static DieCallbackType DieCallback; void SetDieCallback(DieCallbackType callback) { @@ -68,36 +71,6 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond, Die(); } -void MaybeOpenReportFile() { - if (!log_to_file || (report_fd_pid == internal_getpid())) return; - InternalScopedBuffer report_path_full(4096); - internal_snprintf(report_path_full.data(), report_path_full.size(), - "%s.%d", report_path_prefix, internal_getpid()); - uptr openrv = OpenFile(report_path_full.data(), true); - if (internal_iserror(openrv)) { - report_fd = kStderrFd; - log_to_file = false; - Report("ERROR: Can't open file: %s\n", report_path_full.data()); - Die(); - } - if (report_fd != kInvalidFd) { - // We're in the child. Close the parent's log. - internal_close(report_fd); - } - report_fd = openrv; - report_fd_pid = internal_getpid(); -} - -void RawWrite(const char *buffer) { - static const char *kRawWriteError = "RawWrite can't output requested buffer!"; - uptr length = (uptr)internal_strlen(buffer); - MaybeOpenReportFile(); - if (length != internal_write(report_fd, buffer, length)) { - internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError)); - Die(); - } -} - uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr max_len) { uptr PageSize = GetPageSizeCached(); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 7a96a481bc33..abed9440b176 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -116,6 +116,9 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)); extern StaticSpinMutex CommonSanitizerReportMutex; void MaybeOpenReportFile(); extern fd_t report_fd; +extern bool log_to_file; +extern char report_path_prefix[4096]; +extern uptr report_fd_pid; uptr OpenFile(const char *filename, bool write); // Opens the file 'file_name" and reads up to 'max_len' bytes. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc index 0977f2c9f453..a73e7419a426 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -197,6 +197,37 @@ char *FindPathToBinary(const char *name) { return 0; } +void MaybeOpenReportFile() { + if (!log_to_file || (report_fd_pid == internal_getpid())) return; + InternalScopedBuffer report_path_full(4096); + internal_snprintf(report_path_full.data(), report_path_full.size(), + "%s.%d", report_path_prefix, internal_getpid()); + uptr openrv = OpenFile(report_path_full.data(), true); + if (internal_iserror(openrv)) { + report_fd = kStderrFd; + log_to_file = false; + Report("ERROR: Can't open file: %s\n", report_path_full.data()); + Die(); + } + if (report_fd != kInvalidFd) { + // We're in the child. Close the parent's log. + internal_close(report_fd); + } + report_fd = openrv; + report_fd_pid = internal_getpid(); +} + +void RawWrite(const char *buffer) { + static const char *kRawWriteError = + "RawWrite can't output requested buffer!\n"; + uptr length = (uptr)internal_strlen(buffer); + MaybeOpenReportFile(); + if (length != internal_write(report_fd, buffer, length)) { + internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError)); + Die(); + } +} + } // namespace __sanitizer #endif // SANITIZER_LINUX || SANITIZER_MAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc index c3f063fc3133..4c5327ea9622 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -398,6 +398,24 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, stack->trace[i] = (uptr)tmp[i + offset]; } +void MaybeOpenReportFile() { + // Windows doesn't have native fork, and we don't support Cygwin or other + // environments that try to fake it, so the initial report_fd will always be + // correct. +} + +void RawWrite(const char *buffer) { + static const char *kRawWriteError = + "RawWrite can't output requested buffer!\n"; + uptr length = (uptr)internal_strlen(buffer); + if (length != internal_write(report_fd, buffer, length)) { + // stderr may be closed, but we may be able to print to the debugger + // instead. This is the case when launching a program from Visual Studio, + // and the following routine should write to its console. + OutputDebugStringA(buffer); + } +} + } // namespace __sanitizer #endif // _WIN32