diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h index fe0a2fc5ef025..4660a7818c92b 100644 --- a/compiler-rt/include/sanitizer/memprof_interface.h +++ b/compiler-rt/include/sanitizer/memprof_interface.h @@ -59,6 +59,12 @@ const char *SANITIZER_CDECL __memprof_default_options(void); /// \returns 0 on success. int SANITIZER_CDECL __memprof_profile_dump(void); +/// Closes the existing file descriptor, if it is valid and not stdout or +/// stderr, and resets the internal state such that the profile filename is +/// reopened on the next profile dump attempt. This can be used to enable +/// multiple rounds of profiling on the same binary. +void SANITIZER_CDECL __memprof_profile_reset(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp index efdfa5ad04a69..af46ffdb248e2 100644 --- a/compiler-rt/lib/memprof/memprof_allocator.cpp +++ b/compiler-rt/lib/memprof/memprof_allocator.cpp @@ -738,3 +738,13 @@ int __memprof_profile_dump() { // detected during the dumping process. return 0; } + +void __memprof_profile_reset() { + if (report_file.fd != kInvalidFd && report_file.fd != kStdoutFd && + report_file.fd != kStderrFd) { + CloseFile(report_file.fd); + // Setting the file descriptor to kInvalidFd ensures that we will reopen the + // file when invoking Write again. + report_file.fd = kInvalidFd; + } +} diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h index 0aca4afc9afa9..318bc41044056 100644 --- a/compiler-rt/lib/memprof/memprof_interface_internal.h +++ b/compiler-rt/lib/memprof/memprof_interface_internal.h @@ -49,6 +49,7 @@ extern uptr __memprof_shadow_memory_dynamic_address; SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char __memprof_profile_filename[1]; SANITIZER_INTERFACE_ATTRIBUTE int __memprof_profile_dump(); +SANITIZER_INTERFACE_ATTRIBUTE void __memprof_profile_reset(); SANITIZER_INTERFACE_ATTRIBUTE void __memprof_load(uptr p); SANITIZER_INTERFACE_ATTRIBUTE void __memprof_store(uptr p); diff --git a/compiler-rt/test/memprof/TestCases/profile_reset.cpp b/compiler-rt/test/memprof/TestCases/profile_reset.cpp new file mode 100644 index 0000000000000..c9bbc440a29d0 --- /dev/null +++ b/compiler-rt/test/memprof/TestCases/profile_reset.cpp @@ -0,0 +1,39 @@ +// Test to ensure that multiple rounds of dumping, using the +// __memprof_profile_reset interface to close the initial file +// and cause the profile to be reopened, works as expected. + +// RUN: %clangxx_memprof %s -o %t + +// RUN: rm -f %t.log.* +// RUN: %env_memprof_opts=print_text=true:log_path=%t.log %run %t + +// Check both outputs, starting with the renamed initial dump, then remove it so +// that the second glob matches a single file. +// RUN: FileCheck %s < %t.log.*.sv +// RUN: rm -f %t.log.*.sv +// RUN: FileCheck %s < %t.log.* +// CHECK: Memory allocation stack id + +#include +#include + +#include +#include +#include +int main(int argc, char **argv) { + char *x = (char *)malloc(10); + memset(x, 0, 10); + free(x); + __memprof_profile_dump(); + // Save the initial dump in a different file. + std::string origname = __sanitizer_get_report_path(); + std::string svname = origname + ".sv"; + rename(origname.c_str(), svname.c_str()); + // This should cause the current file descriptor to be closed and the + // the internal state reset so that the profile filename is reopened + // on the next write. + __memprof_profile_reset(); + // This will dump to origname again. + __memprof_profile_dump(); + return 0; +}