From 56dec4be9bd321a8fc0f19df00a8d63fc44813f5 Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Tue, 14 Sep 2021 16:34:52 -0700 Subject: [PATCH] [Sanitizer] Allow setting the report path to create directory When setting the report path, recursively create the directory as needed. This brings the profile path support for memprof on par with normal PGO. The code was largely cloned from __llvm_profile_recursive_mkdir in compiler-rt/lib/profile/InstrProfilingUtil.c. Differential Revision: https://reviews.llvm.org/D109794 --- .../sanitizer_common/sanitizer_common_nolibc.cpp | 1 + .../lib/sanitizer_common/sanitizer_file.cpp | 15 +++++++++++++++ compiler-rt/lib/sanitizer_common/sanitizer_file.h | 2 ++ .../sanitizer_common/sanitizer_posix_libcdep.cpp | 2 ++ .../lib/sanitizer_common/sanitizer_win.cpp | 2 ++ .../tests/sanitizer_libc_test.cpp | 14 ++++++++++++++ .../Posix/sanitizer_set_report_path_test.cpp | 4 ++-- 7 files changed, 38 insertions(+), 2 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp index 9a4e5388f24d..a20602d8b95a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp @@ -25,6 +25,7 @@ void LogMessageOnPrintf(const char *str) {} #endif void WriteToSyslog(const char *buffer) {} void Abort() { internal__exit(1); } +bool CreateDir(const char *pathname) { return false; } #endif // !SANITIZER_WINDOWS #if !SANITIZER_WINDOWS && !SANITIZER_MAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp index 0b92dccde4a1..5492560df914 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp @@ -75,6 +75,20 @@ void ReportFile::ReopenIfNecessary() { fd_pid = pid; } +static void RecursiveCreateParentDirs(char *path) { + if (path[0] == '\0') + return; + for (int i = 1; path[i] != '\0'; ++i) { + char save = path[i]; + if (!IsPathSeparator(path[i])) + continue; + path[i] = '\0'; + /* Some of these will fail, because the directory exists, ignore it. */ + CreateDir(path); + path[i] = save; + } +} + void ReportFile::SetReportPath(const char *path) { if (path) { uptr len = internal_strlen(path); @@ -95,6 +109,7 @@ void ReportFile::SetReportPath(const char *path) { fd = kStdoutFd; } else { internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + RecursiveCreateParentDirs(path_prefix); } } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.h b/compiler-rt/lib/sanitizer_common/sanitizer_file.h index 08671ab67d0f..3d7916171c1e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_file.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.h @@ -81,6 +81,8 @@ bool FileExists(const char *filename); char *FindPathToBinary(const char *name); bool IsPathSeparator(const char c); bool IsAbsolutePath(const char *path); +// Returns true on success, false on failure. +bool CreateDir(const char *pathname); // Starts a subprocess and returs its pid. // If *_fd parameters are not kInvalidFd their corresponding input/output // streams will be redirect to the file. The files will always be closed diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index ddf6844bed13..eed02ce4f6aa 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -151,6 +151,8 @@ int Atexit(void (*function)(void)) { #endif } +bool CreateDir(const char *pathname) { return mkdir(pathname, 0755) == 0; } + bool SupportsColoredOutput(fd_t fd) { return isatty(fd) != 0; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index 1c8d1b69d66f..491b84f943df 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -565,6 +565,8 @@ void Abort() { internal__exit(3); } +bool CreateDir(const char *pathname) { return _mkdir(pathname) == 0; } + #if !SANITIZER_GO // Read the file to extract the ImageBase field from the PE header. If ASLR is // disabled and this virtual address is available, the loader will typically diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cpp index c4fbb4e5c9f6..97737e2a1fc2 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cpp @@ -326,3 +326,17 @@ TEST(SanitizerCommon, InternalMmapWithOffset) { internal_unlink(tmpfile); } #endif + +TEST(SanitizerCommon, ReportFile) { + StaticSpinMutex report_file_mu; + ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; + char tmpfile[128]; + temp_file_name(tmpfile, sizeof(tmpfile), + "dir/sanitizer_common.reportfile.tmp."); + report_file.SetReportPath(tmpfile); + const char *path = report_file.GetReportPath(); + EXPECT_EQ(internal_strncmp(tmpfile, path, strlen(tmpfile)), 0); + // This will close tmpfile. + report_file.SetReportPath("stderr"); + Unlink(tmpfile); +} 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 e5ea040168f2..17cee722749d 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 @@ -11,10 +11,10 @@ volatile int *null = 0; int main(int argc, char **argv) { char buff[1000]; - sprintf(buff, "%s.report_path", argv[0]); + sprintf(buff, "%s.report_path/report", argv[0]); __sanitizer_set_report_path(buff); assert(strncmp(buff, __sanitizer_get_report_path(), strlen(buff)) == 0); printf("Path %s\n", __sanitizer_get_report_path()); } -// CHECK: Path {{.*}}Posix/Output/sanitizer_set_report_path_test.cpp.tmp.report_path. +// CHECK: Path {{.*}}Posix/Output/sanitizer_set_report_path_test.cpp.tmp.report_path/report.