[compiler-rt] 5301f4c - [Sanitizer] Use % patterns in report paths (#141820)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 30 07:57:54 PDT 2025
Author: Ellis Hoag
Date: 2025-05-30T07:57:51-07:00
New Revision: 5301f4c469de1cd410dbc2fc953ead14296d4eb0
URL: https://github.com/llvm/llvm-project/commit/5301f4c469de1cd410dbc2fc953ead14296d4eb0
DIFF: https://github.com/llvm/llvm-project/commit/5301f4c469de1cd410dbc2fc953ead14296d4eb0.diff
LOG: [Sanitizer] Use % patterns in report paths (#141820)
Support `%` patterns in sanitizer report paths, similar to the patterns
supported in IRPGO
https://github.com/llvm/llvm-project/blob/4bf67cdf026478c4bc3e708153c02f82e2c22524/compiler-rt/lib/profile/InstrProfilingFile.c#L999-L1017
* `%%` becomes `%`
* `%H` expands to the environment variable `HOME`
* `%t` expands to the environment variable `TMPDIR`
* `%p` expands to the process ID (PID)
In particular, the `%H` pattern is useful to resolve the home directory
at runtime, which is not possible before this PR.
Also, avoid using `Report()` before the report path has been set.
Added:
compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_fail.cpp
Modified:
compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_test.cpp
Removed:
################################################################################
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 <sanitizer/common_interface_defs.h>
+#include <stdio.h>
+
+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 <assert.h>
#include <sanitizer/common_interface_defs.h>
#include <stdio.h>
#include <string.h>
-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());
+}
More information about the llvm-commits
mailing list