diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp @@ -25,6 +25,7 @@ #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.h b/compiler-rt/lib/sanitizer_common/sanitizer_file.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_file.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.h @@ -81,6 +81,8 @@ 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_file.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.cpp @@ -75,6 +75,20 @@ 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 @@ fd = kStdoutFd; } else { internal_snprintf(path_prefix, kMaxPathLength, "%s", path); + RecursiveCreateParentDirs(path_prefix); } } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -151,6 +151,8 @@ #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 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -565,6 +565,8 @@ 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 --- 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 @@ 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 --- 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 @@ 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.