[compiler-rt] [Sanitizer] Use % patterns in report paths (PR #141820)

Ellis Hoag via llvm-commits llvm-commits at lists.llvm.org
Thu May 29 10:33:44 PDT 2025


https://github.com/ellishg updated https://github.com/llvm/llvm-project/pull/141820

>From 905e59e453e0086d63555becd8eefcdabd2c9d4f Mon Sep 17 00:00:00 2001
From: Ellis Hoag <ellishoag at meta.com>
Date: Wed, 28 May 2025 11:34:52 -0700
Subject: [PATCH 1/2] [Sanitizer] Use % patterns in report paths

---
 .../lib/sanitizer_common/sanitizer_file.cpp   | 69 ++++++++++++++++++-
 .../Posix/sanitizer_set_report_path_fail.cpp  | 19 +++++
 .../Posix/sanitizer_set_report_path_test.cpp  | 45 ++++++++----
 3 files changed, 115 insertions(+), 18 deletions(-)
 create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_fail.cpp

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
index 96af270f9d8b5..b55c4ff093c1b 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
@@ -96,12 +96,75 @@ 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_GT(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);
+      WriteToFile(kStderrFd, "\n", internal_strlen("\n"));
       Die();
     }
   }
@@ -115,7 +178,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..c86e1e7e25522
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_path_fail.cpp
@@ -0,0 +1,19 @@
+// RUN: %clangxx -O2 %s -o %t
+// RUN: not %env %run %t 2>&1 | FileCheck %s --check-prefix=ERROR1
+// 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) {
+    // Try setting again with an invalid/inaccessible directory.
+    sprintf(buff, "%s/report", argv[0]);
+    // ERROR1: Can't create directory: {{.*}}
+  } else {
+    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());
+}

>From caaa557d86b664c04c0f4a7f1e6817311cd780c9 Mon Sep 17 00:00:00 2001
From: Ellis Hoag <ellishoag at meta.com>
Date: Thu, 29 May 2025 10:33:28 -0700
Subject: [PATCH 2/2] resolve some comments

---
 compiler-rt/lib/sanitizer_common/sanitizer_file.cpp            | 3 ++-
 .../TestCases/Posix/sanitizer_set_report_path_fail.cpp         | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
index b55c4ff093c1b..a61be71e603e2 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp
@@ -164,7 +164,8 @@ void ReportFile::SetReportPath(const char *path) {
       const char *message = "ERROR: Path is too long: ";
       WriteToFile(kStderrFd, message, internal_strlen(message));
       WriteToFile(kStderrFd, path, 8);
-      WriteToFile(kStderrFd, "\n", internal_strlen("\n"));
+      message = "...\n";
+      WriteToFile(kStderrFd, message, internal_strlen(message));
       Die();
     }
   }
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
index c86e1e7e25522..7c4af8b3477a0 100644
--- 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
@@ -12,8 +12,9 @@ int main(int argc, char **argv) {
     sprintf(buff, "%s/report", argv[0]);
     // ERROR1: Can't create directory: {{.*}}
   } else {
+    // Try setting a path that is too large.
     snprintf(buff, sizeof(buff), "%04095d", 42);
-    // ERROR2: Path is too long: 00000000
+    // ERROR2: Path is too long: 00000000...
   }
   __sanitizer_set_report_path(buff);
 }



More information about the llvm-commits mailing list