diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp index 96af270f9d8b5..9236a458cdb0e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp @@ -96,12 +96,76 @@ static void RecursiveCreateParentDirs(char *path) { } } +/// Parse the report path \p pattern and copy the parsed path to \p dest. +/// +/// * `%%` becomes `%` +/// * `%H` expands to the environment variable `HOME` +/// * `%t` expands to the environment variable `TMPDIR` +/// * `%p` expands to the process ID (PID) +static void ParseAndSetPath(const char *pattern, char *dest, + const uptr dest_size) { + CHECK(pattern); + CHECK(dest); + CHECK_GE(dest_size, 1); + dest[0] = '\0'; + uptr next_substr_start_idx = 0; + for (uptr i = 0; i < internal_strlen(pattern) - 1; i++) { + if (pattern[i] != '%') + continue; + int bytes_to_copy = i - next_substr_start_idx; + // Copy over previous substring. + CHECK_LT(internal_strlcat(dest, pattern + next_substr_start_idx, + internal_strlen(dest) + bytes_to_copy + 1), + dest_size); + const char *str_to_concat; + switch (pattern[++i]) { + case '%': + str_to_concat = "%"; + break; + case 'H': + str_to_concat = GetEnv("HOME"); + break; + case 't': + str_to_concat = GetEnv("TMPDIR"); + break; + case 'p': { + // Use printf directly to write the PID since it's not a static string. + int remaining_capacity = dest_size - internal_strlen(dest); + int bytes_copied = + internal_snprintf(dest + internal_strlen(dest), remaining_capacity, + "%ld", internal_getpid()); + CHECK_GT(bytes_copied, 0); + CHECK_LT(bytes_copied, remaining_capacity); + str_to_concat = ""; + break; + } + default: { + // Invalid pattern: fallback to original pattern. + const char *message = "ERROR: Unexpected pattern: "; + WriteToFile(kStderrFd, message, internal_strlen(message)); + WriteToFile(kStderrFd, pattern, internal_strlen(pattern)); + WriteToFile(kStderrFd, "\n", internal_strlen("\n")); + CHECK_LT(internal_strlcpy(dest, pattern, dest_size), dest_size); + return; + } + } + CHECK(str_to_concat); + CHECK_LT(internal_strlcat(dest, str_to_concat, dest_size), dest_size); + next_substr_start_idx = i + 1; + } + CHECK_LT(internal_strlcat(dest, pattern + next_substr_start_idx, dest_size), + dest_size); +} + void ReportFile::SetReportPath(const char *path) { if (path) { uptr len = internal_strlen(path); if (len > sizeof(path_prefix) - 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]); + const char *message = "ERROR: Path is too long: "; + WriteToFile(kStderrFd, message, internal_strlen(message)); + WriteToFile(kStderrFd, path, 8); + message = "...\n"; + WriteToFile(kStderrFd, message, internal_strlen(message)); Die(); } } @@ -115,7 +179,7 @@ void ReportFile::SetReportPath(const char *path) { } else if (internal_strcmp(path, "stdout") == 0) { fd = kStdoutFd; } else { - internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + ParseAndSetPath(path, path_prefix, kMaxPathLength); RecursiveCreateParentDirs(path_prefix); } } diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_fail.cpp b/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_fail.cpp new file mode 100644 index 0000000000000..782cd0218fd22 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_fail.cpp @@ -0,0 +1,24 @@ +// RUN: %clangxx -O2 %s -o %t + +// Case 1: Try setting a path that is an invalid/inaccessible directory. +// RUN: not %env %run %t 2>&1 | FileCheck %s --check-prefix=ERROR1 + +// Case 2: Try setting a path that is too large. +// RUN: not %env %run %t A 2>&1 | FileCheck %s --check-prefix=ERROR2 + +#include +#include + +int main(int argc, char **argv) { + char buff[4096]; + if (argc == 1) { + // Case 1 + sprintf(buff, "%s/report", argv[0]); + // ERROR1: Can't create directory: {{.*}} + } else { + // Case 2 + snprintf(buff, sizeof(buff), "%04095d", 42); + // ERROR2: Path is too long: 00000000... + } + __sanitizer_set_report_path(buff); +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp b/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp index ab1017a2efc07..9d7ed80b44ccb 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp @@ -1,27 +1,42 @@ // Test __sanitizer_set_report_path and __sanitizer_get_report_path: // RUN: %clangxx -O2 %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: %env HOME=%t.homedir TMPDIR=%t.tmpdir %run %t 2>%t.err | FileCheck %s +// RUN: FileCheck %s --input-file=%t.err --check-prefix=ERROR -#include #include #include #include -volatile int *null = 0; - int main(int argc, char **argv) { - char buff[1000]; + char buff[4096]; sprintf(buff, "%s.report_path/report", argv[0]); __sanitizer_set_report_path(buff); - assert(strncmp(buff, __sanitizer_get_report_path(), strlen(buff)) == 0); + // CHECK: {{.*}}.report_path/report.[[PID:[0-9]+]] + printf("%s\n", __sanitizer_get_report_path()); - // Try setting again with an invalid/inaccessible directory. - char buff_bad[1000]; - sprintf(buff_bad, "%s/report", argv[0]); - fprintf(stderr, "Expected bad report path: %s\n", buff_bad); - // CHECK: Expected bad report path: [[BADPATH:.*]]/report - __sanitizer_set_report_path(buff_bad); - assert(strncmp(buff, __sanitizer_get_report_path(), strlen(buff)) == 0); -} + strcpy(buff, "%H/foo"); + __sanitizer_set_report_path(buff); + // CHECK: [[T:.*]].homedir/foo.[[PID]] + printf("%s\n", __sanitizer_get_report_path()); -// CHECK: ERROR: Can't create directory: [[BADPATH]] + strcpy(buff, "%t/foo"); + __sanitizer_set_report_path(buff); + // CHECK: [[T]].tmpdir/foo.[[PID]] + printf("%s\n", __sanitizer_get_report_path()); + + strcpy(buff, "%H/%p/%%foo"); + __sanitizer_set_report_path(buff); + // CHECK: [[T]].homedir/[[PID]]/%foo.[[PID]] + printf("%s\n", __sanitizer_get_report_path()); + + strcpy(buff, "%%foo%%bar"); + __sanitizer_set_report_path(buff); + // CHECK: %foo%bar.[[PID]] + printf("%s\n", __sanitizer_get_report_path()); + + strcpy(buff, "%%foo%ba%%r"); + __sanitizer_set_report_path(buff); + // ERROR: Unexpected pattern: %%foo%ba%%r + // CHECK: %%foo%ba%%r.[[PID]] + printf("%s\n", __sanitizer_get_report_path()); +}