Skip to content

Commit 8843111

Browse files
authored
[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.
1 parent 72f3b1c commit 8843111

File tree

4 files changed

+47
-14
lines changed

4 files changed

+47
-14
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_file.cpp

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,17 @@ void RawWrite(const char *buffer) {
3636

3737
void ReportFile::ReopenIfNecessary() {
3838
mu->CheckLocked();
39-
if (fd == kStdoutFd || fd == kStderrFd) return;
40-
4139
uptr pid = internal_getpid();
40+
if (fallbackToStderrActive && fd_pid != pid) {
41+
// If fallbackToStderrActive is set then we fellback to stderr. If this is a
42+
// new process, mark fd as invalid so we attempt to open again.
43+
CHECK_EQ(fd, kStderrFd);
44+
fd = kInvalidFd;
45+
fallbackToStderrActive = false;
46+
}
47+
if (fd == kStdoutFd || fd == kStderrFd)
48+
return;
49+
4250
// If in tracer, use the parent's file.
4351
if (pid == stoptheworld_tracer_pid)
4452
pid = stoptheworld_tracer_ppid;
@@ -48,8 +56,7 @@ void ReportFile::ReopenIfNecessary() {
4856
// process, close it now.
4957
if (fd_pid == pid)
5058
return;
51-
else
52-
CloseFile(fd);
59+
CloseFile(fd);
5360
}
5461

5562
const char *exe_name = GetProcessName();
@@ -65,18 +72,24 @@ void ReportFile::ReopenIfNecessary() {
6572
error_t err;
6673
fd = OpenFile(full_path, WrOnly, &err);
6774
if (fd == kInvalidFd) {
68-
const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
75+
bool fallback = common_flags()->log_fallback_to_stderr;
76+
const char *ErrorMsgPrefix =
77+
fallback ? "WARNING: Can't open file, falling back to stderr: "
78+
: "ERROR: Can't open file: ";
6979
WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
7080
WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
7181
char errmsg[100];
7282
internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)\n", err);
7383
WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg));
74-
Die();
84+
if (!fallback)
85+
Die();
86+
fallbackToStderrActive = true;
87+
fd = kStderrFd;
7588
}
7689
fd_pid = pid;
7790
}
7891

79-
static void RecursiveCreateParentDirs(char *path) {
92+
static void RecursiveCreateParentDirs(char *path, fd_t &fd) {
8093
if (path[0] == '\0')
8194
return;
8295
for (int i = 1; path[i] != '\0'; ++i) {
@@ -85,12 +98,19 @@ static void RecursiveCreateParentDirs(char *path) {
8598
continue;
8699
path[i] = '\0';
87100
if (!DirExists(path) && !CreateDir(path)) {
88-
const char *ErrorMsgPrefix = "ERROR: Can't create directory: ";
101+
bool fallback = common_flags()->log_fallback_to_stderr;
102+
const char *ErrorMsgPrefix =
103+
fallback ? "WARNING: Can't create directory, falling back to stderr: "
104+
: "ERROR: Can't create directory: ";
89105
WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
90106
WriteToFile(kStderrFd, path, internal_strlen(path));
91107
const char *ErrorMsgSuffix = "\n";
92108
WriteToFile(kStderrFd, ErrorMsgSuffix, internal_strlen(ErrorMsgSuffix));
93-
Die();
109+
if (!fallback)
110+
Die();
111+
path[i] = save;
112+
fd = kStderrFd;
113+
return;
94114
}
95115
path[i] = save;
96116
}
@@ -164,12 +184,17 @@ void ReportFile::SetReportPath(const char *path) {
164184
if (path) {
165185
uptr len = internal_strlen(path);
166186
if (len > sizeof(path_prefix) - 100) {
167-
const char *message = "ERROR: Path is too long: ";
187+
bool fallback = common_flags()->log_fallback_to_stderr;
188+
const char *message =
189+
fallback ? "WARNING: Path is too long, falling back to stderr: "
190+
: "ERROR: Path is too long: ";
168191
WriteToFile(kStderrFd, message, internal_strlen(message));
169192
WriteToFile(kStderrFd, path, 8);
170193
message = "...\n";
171194
WriteToFile(kStderrFd, message, internal_strlen(message));
172-
Die();
195+
if (!fallback)
196+
Die();
197+
path = "stderr";
173198
}
174199
}
175200

@@ -183,7 +208,7 @@ void ReportFile::SetReportPath(const char *path) {
183208
fd = kStdoutFd;
184209
} else {
185210
ParseAndSetPath(path, path_prefix, kMaxPathLength);
186-
RecursiveCreateParentDirs(path_prefix);
211+
RecursiveCreateParentDirs(path_prefix, fd);
187212
}
188213
}
189214

compiler-rt/lib/sanitizer_common/sanitizer_file.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ struct ReportFile {
4343
// PID of the process that opened fd. If a fork() occurs,
4444
// the PID of child will be different from fd_pid.
4545
uptr fd_pid;
46+
// Set to true if the last attempt to open the logfile failed, perhaps due to
47+
// permission errors
48+
bool fallbackToStderrActive = false;
4649

4750
private:
4851
void ReopenIfNecessary();

compiler-rt/lib/sanitizer_common/sanitizer_flags.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ COMMON_FLAG(
6565
bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_APPLE,
6666
"Write all sanitizer output to syslog in addition to other means of "
6767
"logging.")
68+
COMMON_FLAG(bool, log_fallback_to_stderr, false,
69+
"When set, fallback to stderr if we are unable to open log path.")
6870
COMMON_FLAG(
6971
int, verbosity, 0,
7072
"Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).")

compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_fail.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
// Case 1: Try setting a path that is an invalid/inaccessible directory.
44
// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=ERROR1
5+
// RUN: %env_tool_opts=log_fallback_to_stderr=true %run %t 2>&1 | FileCheck %s --check-prefixes=ERROR1,FALLBACK
56

67
// Case 2: Try setting a path that is too large.
78
// RUN: not %run %t A 2>&1 | FileCheck %s --check-prefix=ERROR2
9+
// RUN: %env_tool_opts=log_fallback_to_stderr=true %run %t A 2>&1 | FileCheck %s --check-prefixes=ERROR2,FALLBACK
810

911
#include <sanitizer/common_interface_defs.h>
1012
#include <stdio.h>
@@ -14,11 +16,12 @@ int main(int argc, char **argv) {
1416
if (argc == 1) {
1517
// Case 1
1618
sprintf(buff, "%s/report", argv[0]);
17-
// ERROR1: Can't create directory: {{.*}}
19+
// ERROR1: Can't create directory
1820
} else {
1921
// Case 2
2022
snprintf(buff, sizeof(buff), "%04095d", 42);
21-
// ERROR2: Path is too long: 00000000...
23+
// ERROR2: Path is too long
2224
}
2325
__sanitizer_set_report_path(buff);
2426
}
27+
// FALLBACK: falling back to stderr

0 commit comments

Comments
 (0)