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
This commit is contained in:
Reid Kleckner 2013-09-05 03:19:57 +00:00
parent 2f58696ddd
commit d483c072af
4 changed files with 58 additions and 33 deletions

View File

@ -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.<PID>".
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<char> 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();

View File

@ -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.

View File

@ -197,6 +197,37 @@ char *FindPathToBinary(const char *name) {
return 0;
}
void MaybeOpenReportFile() {
if (!log_to_file || (report_fd_pid == internal_getpid())) return;
InternalScopedBuffer<char> 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

View File

@ -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