mirror of
https://github.com/intel/llvm.git
synced 2026-01-22 23:49:22 +08:00
[Sanitizer] Option to fallback to stderr if unable to open logfile (#158687)
Add the santizier option `log_fallback_to_stderr` which will set the logpath to `stderr` if there is an error with the provided logpath. We've seen this happen when process A has write permission to the logpath, but process B does not. In this case, we'd like process B to fallback to writing to `stderr`, rather than being killed.
This commit is contained in:
@@ -36,9 +36,17 @@ void RawWrite(const char *buffer) {
|
||||
|
||||
void ReportFile::ReopenIfNecessary() {
|
||||
mu->CheckLocked();
|
||||
if (fd == kStdoutFd || fd == kStderrFd) return;
|
||||
|
||||
uptr pid = internal_getpid();
|
||||
if (fallbackToStderrActive && fd_pid != pid) {
|
||||
// If fallbackToStderrActive is set then we fellback to stderr. If this is a
|
||||
// new process, mark fd as invalid so we attempt to open again.
|
||||
CHECK_EQ(fd, kStderrFd);
|
||||
fd = kInvalidFd;
|
||||
fallbackToStderrActive = false;
|
||||
}
|
||||
if (fd == kStdoutFd || fd == kStderrFd)
|
||||
return;
|
||||
|
||||
// If in tracer, use the parent's file.
|
||||
if (pid == stoptheworld_tracer_pid)
|
||||
pid = stoptheworld_tracer_ppid;
|
||||
@@ -48,8 +56,7 @@ void ReportFile::ReopenIfNecessary() {
|
||||
// process, close it now.
|
||||
if (fd_pid == pid)
|
||||
return;
|
||||
else
|
||||
CloseFile(fd);
|
||||
CloseFile(fd);
|
||||
}
|
||||
|
||||
const char *exe_name = GetProcessName();
|
||||
@@ -65,18 +72,24 @@ void ReportFile::ReopenIfNecessary() {
|
||||
error_t err;
|
||||
fd = OpenFile(full_path, WrOnly, &err);
|
||||
if (fd == kInvalidFd) {
|
||||
const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
|
||||
bool fallback = common_flags()->log_fallback_to_stderr;
|
||||
const char *ErrorMsgPrefix =
|
||||
fallback ? "WARNING: Can't open file, falling back to stderr: "
|
||||
: "ERROR: Can't open file: ";
|
||||
WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
|
||||
WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
|
||||
char errmsg[100];
|
||||
internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)\n", err);
|
||||
WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg));
|
||||
Die();
|
||||
if (!fallback)
|
||||
Die();
|
||||
fallbackToStderrActive = true;
|
||||
fd = kStderrFd;
|
||||
}
|
||||
fd_pid = pid;
|
||||
}
|
||||
|
||||
static void RecursiveCreateParentDirs(char *path) {
|
||||
static void RecursiveCreateParentDirs(char *path, fd_t &fd) {
|
||||
if (path[0] == '\0')
|
||||
return;
|
||||
for (int i = 1; path[i] != '\0'; ++i) {
|
||||
@@ -85,12 +98,19 @@ static void RecursiveCreateParentDirs(char *path) {
|
||||
continue;
|
||||
path[i] = '\0';
|
||||
if (!DirExists(path) && !CreateDir(path)) {
|
||||
const char *ErrorMsgPrefix = "ERROR: Can't create directory: ";
|
||||
bool fallback = common_flags()->log_fallback_to_stderr;
|
||||
const char *ErrorMsgPrefix =
|
||||
fallback ? "WARNING: Can't create directory, falling back to stderr: "
|
||||
: "ERROR: Can't create directory: ";
|
||||
WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
|
||||
WriteToFile(kStderrFd, path, internal_strlen(path));
|
||||
const char *ErrorMsgSuffix = "\n";
|
||||
WriteToFile(kStderrFd, ErrorMsgSuffix, internal_strlen(ErrorMsgSuffix));
|
||||
Die();
|
||||
if (!fallback)
|
||||
Die();
|
||||
path[i] = save;
|
||||
fd = kStderrFd;
|
||||
return;
|
||||
}
|
||||
path[i] = save;
|
||||
}
|
||||
@@ -164,12 +184,17 @@ void ReportFile::SetReportPath(const char *path) {
|
||||
if (path) {
|
||||
uptr len = internal_strlen(path);
|
||||
if (len > sizeof(path_prefix) - 100) {
|
||||
const char *message = "ERROR: Path is too long: ";
|
||||
bool fallback = common_flags()->log_fallback_to_stderr;
|
||||
const char *message =
|
||||
fallback ? "WARNING: Path is too long, falling back to stderr: "
|
||||
: "ERROR: Path is too long: ";
|
||||
WriteToFile(kStderrFd, message, internal_strlen(message));
|
||||
WriteToFile(kStderrFd, path, 8);
|
||||
message = "...\n";
|
||||
WriteToFile(kStderrFd, message, internal_strlen(message));
|
||||
Die();
|
||||
if (!fallback)
|
||||
Die();
|
||||
path = "stderr";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +208,7 @@ void ReportFile::SetReportPath(const char *path) {
|
||||
fd = kStdoutFd;
|
||||
} else {
|
||||
ParseAndSetPath(path, path_prefix, kMaxPathLength);
|
||||
RecursiveCreateParentDirs(path_prefix);
|
||||
RecursiveCreateParentDirs(path_prefix, fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ struct ReportFile {
|
||||
// PID of the process that opened fd. If a fork() occurs,
|
||||
// the PID of child will be different from fd_pid.
|
||||
uptr fd_pid;
|
||||
// Set to true if the last attempt to open the logfile failed, perhaps due to
|
||||
// permission errors
|
||||
bool fallbackToStderrActive = false;
|
||||
|
||||
private:
|
||||
void ReopenIfNecessary();
|
||||
|
||||
@@ -65,6 +65,8 @@ COMMON_FLAG(
|
||||
bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_APPLE,
|
||||
"Write all sanitizer output to syslog in addition to other means of "
|
||||
"logging.")
|
||||
COMMON_FLAG(bool, log_fallback_to_stderr, false,
|
||||
"When set, fallback to stderr if we are unable to open log path.")
|
||||
COMMON_FLAG(
|
||||
int, verbosity, 0,
|
||||
"Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).")
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
// Case 1: Try setting a path that is an invalid/inaccessible directory.
|
||||
// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=ERROR1
|
||||
// RUN: %env_tool_opts=log_fallback_to_stderr=true %run %t 2>&1 | FileCheck %s --check-prefixes=ERROR1,FALLBACK
|
||||
|
||||
// Case 2: Try setting a path that is too large.
|
||||
// RUN: not %run %t A 2>&1 | FileCheck %s --check-prefix=ERROR2
|
||||
// RUN: %env_tool_opts=log_fallback_to_stderr=true %run %t A 2>&1 | FileCheck %s --check-prefixes=ERROR2,FALLBACK
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
#include <stdio.h>
|
||||
@@ -14,11 +16,12 @@ int main(int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
// Case 1
|
||||
sprintf(buff, "%s/report", argv[0]);
|
||||
// ERROR1: Can't create directory: {{.*}}
|
||||
// ERROR1: Can't create directory
|
||||
} else {
|
||||
// Case 2
|
||||
snprintf(buff, sizeof(buff), "%04095d", 42);
|
||||
// ERROR2: Path is too long: 00000000...
|
||||
// ERROR2: Path is too long
|
||||
}
|
||||
__sanitizer_set_report_path(buff);
|
||||
}
|
||||
// FALLBACK: falling back to stderr
|
||||
|
||||
Reference in New Issue
Block a user