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 @@ -78,6 +78,7 @@ // OS const char *GetPwd(); bool FileExists(const char *filename); +bool DirExists(const char *path); char *FindPathToBinary(const char *name); bool IsPathSeparator(const char c); bool IsAbsolutePath(const char *path); 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 @@ -83,8 +83,14 @@ if (!IsPathSeparator(path[i])) continue; path[i] = '\0'; - /* Some of these will fail, because the directory exists, ignore it. */ - CreateDir(path); + if (!DirExists(path)) { + if (!CreateDir(path)) { + const char *ErrorMsgPrefix = "ERROR: Can't create directory: "; + WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); + WriteToFile(kStderrFd, path, internal_strlen(path)); + Die(); + } + } path[i] = save; } } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -499,6 +499,17 @@ return S_ISREG(st.st_mode); } +bool DirExists(const char *path) { + struct stat st; +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, path, &st, 0)) +#else + if (internal_stat(path, &st)) +#endif + return false; + return S_ISDIR(st.st_mode); +} + #if !SANITIZER_NETBSD tid_t GetTid() { #if SANITIZER_FREEBSD diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -392,6 +392,13 @@ return S_ISREG(st.st_mode); } +bool DirExists(const char *path) { + struct stat st; + if (stat(path, &st)) + return false; + return S_ISDIR(st.st_mode); +} + tid_t GetTid() { tid_t tid; pthread_threadid_np(nullptr, &tid); 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 @@ -93,6 +93,11 @@ return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; } +bool DirExists(const char *path) { + auto attr = ::GetFileAttributesA(path); + return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY); +} + uptr internal_getpid() { return GetProcessId(GetCurrentProcess()); } diff --git a/compiler-rt/test/asan/TestCases/log-path_test.cpp b/compiler-rt/test/asan/TestCases/log-path_test.cpp --- a/compiler-rt/test/asan/TestCases/log-path_test.cpp +++ b/compiler-rt/test/asan/TestCases/log-path_test.cpp @@ -16,10 +16,14 @@ // RUN: %env_asan_opts=log_path=%t.log not %run %t 2> %t.out // RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.* -// Invalid log_path. -// RUN: %env_asan_opts=log_path=/dev/null/INVALID not %run %t 2> %t.out +// Invalid log_path in existing directory. +// RUN: %env_asan_opts=log_path=/INVALID not %run %t 2> %t.out // RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out +// Directory of log_path can't be created. +// RUN: %env_asan_opts=log_path=/dev/null/INVALID not %run %t 2> %t.out +// RUN: FileCheck %s --check-prefix=CHECK-BAD-DIR < %t.out + // Too long log_path. // RUN: %env_asan_opts=log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \ // RUN: not %run %t 2> %t.out @@ -44,5 +48,6 @@ return res; } // CHECK-ERROR: ERROR: AddressSanitizer -// CHECK-INVALID: ERROR: Can't open file: /dev/null/INVALID +// CHECK-INVALID: ERROR: Can't open file: /INVALID +// CHECK-BAD-DIR: ERROR: Can't create directory: /dev/null // CHECK-LONG: ERROR: Path is too long: 01234 diff --git a/compiler-rt/test/memprof/TestCases/log_path_test.cpp b/compiler-rt/test/memprof/TestCases/log_path_test.cpp --- a/compiler-rt/test/memprof/TestCases/log_path_test.cpp +++ b/compiler-rt/test/memprof/TestCases/log_path_test.cpp @@ -3,18 +3,21 @@ // // RUN: %clangxx_memprof %s -o %t -// stderr print_text=true:log_path +// stderr log_path // RUN: %env_memprof_opts=print_text=true:log_path=stderr %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-GOOD --dump-input=always -// Good print_text=true:log_path. +// Good log_path. // RUN: rm -f %t.log.* // RUN: %env_memprof_opts=print_text=true:log_path=%t.log %run %t // RUN: FileCheck %s --check-prefix=CHECK-GOOD --dump-input=always < %t.log.* -// Invalid print_text=true:log_path. -// RUN: %env_memprof_opts=print_text=true:log_path=/dev/null/INVALID not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID --dump-input=always +// Invalid log_path. +// RUN: %env_memprof_opts=print_text=true:log_path=/INVALID not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID --dump-input=always -// Too long print_text=true:log_path. +// Directory of log_path can't be created. +// RUN: %env_memprof_opts=print_text=true:log_path=/dev/null/INVALID not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-BAD-DIR --dump-input=always + +// Too long log_path. // RUN: %env_memprof_opts=print_text=true:log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \ // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LONG --dump-input=always @@ -24,7 +27,7 @@ // Using an automatically generated name via %t can cause weird issues with // unexpected macro expansion if the path includes tokens that match a build // system macro (e.g. "linux"). -// RUN: %clangxx_memprof %s -o %t -DPROFILE_NAME_VAR="/dev/null/INVALID" +// RUN: %clangxx_memprof %s -o %t -DPROFILE_NAME_VAR="/INVALID" // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID --dump-input=always #include @@ -45,5 +48,6 @@ return 0; } // CHECK-GOOD: Memory allocation stack id -// CHECK-INVALID: ERROR: Can't open file: /dev/null/INVALID +// CHECK-INVALID: ERROR: Can't open file: /INVALID +// CHECK-BAD-DIR: ERROR: Can't create directory: /dev/null // CHECK-LONG: ERROR: Path is too long: 01234 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 @@ -1,6 +1,11 @@ // Test __sanitizer_set_report_path and __sanitizer_get_report_path: +// RUN: rm -rf %t.report_path // RUN: %clangxx -O2 %s -o %t // RUN: %run %t | FileCheck %s +// Try again with a directory without write access. +// RUN: rm -rf %t.report_path && mkdir -p %t.report_path +// RUN: chmod u-w %t.report_path || true +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=FAIL #include #include @@ -18,3 +23,4 @@ } // CHECK: Path {{.*}}Posix/Output/sanitizer_set_report_path_test.cpp.tmp.report_path/report. +// FAIL: ERROR: Can't open file: {{.*}}Posix/Output/sanitizer_set_report_path_test.cpp.tmp.report_path/report.