Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -137,6 +137,7 @@ cf->handle_ioctl = false; cf->log_path = 0; cf->detect_leaks = false; + cf->leak_check_at_exit = true; internal_memset(f, 0, sizeof(*f)); f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28; @@ -556,7 +557,7 @@ #if CAN_SANITIZE_LEAKS __lsan::InitCommonLsan(); - if (common_flags()->detect_leaks) { + if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { Atexit(__lsan::DoLeakCheck); } #endif // CAN_SANITIZE_LEAKS Index: lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc =================================================================== --- /dev/null +++ lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc @@ -0,0 +1,19 @@ +// Test for the leak_check_at_exit flag. +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS="verbosity=1" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: LSAN_OPTIONS="verbosity=1" %t 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont + +#include +#include + +int main(int argc, char *argv[]) { + printf("printf to break optimization\n"); + if (argc > 1) + __lsan_do_leak_check(); + return 0; +} + +// CHECK-do: SUMMARY: LeakSanitizer: +// CHECK-dont-NOT: SUMMARY: LeakSanitizer: Index: lib/lsan/lsan.cc =================================================================== --- lib/lsan/lsan.cc +++ lib/lsan/lsan.cc @@ -31,6 +31,7 @@ cf->fast_unwind_on_malloc = true; cf->malloc_context_size = 30; cf->detect_leaks = true; + cf->leak_check_at_exit = true; ParseCommonFlagsFromString(GetEnv("LSAN_OPTIONS")); } @@ -59,7 +60,8 @@ } InitCommonLsan(); - Atexit(DoLeakCheck); + if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) + Atexit(DoLeakCheck); } } // namespace __lsan Index: lib/sanitizer_common/sanitizer_flags.h =================================================================== --- lib/sanitizer_common/sanitizer_flags.h +++ lib/sanitizer_common/sanitizer_flags.h @@ -41,6 +41,10 @@ const char *log_path; // Enable memory leak detection. bool detect_leaks; + // Invoke leak checking in an atexit handler. Has no effect if + // detect_leaks=false, or if __lsan_do_leak_check() is called before the + // handler has a chance to run. + bool leak_check_at_exit; }; extern CommonFlags common_flags_dont_use_directly; Index: lib/sanitizer_common/sanitizer_flags.cc =================================================================== --- lib/sanitizer_common/sanitizer_flags.cc +++ lib/sanitizer_common/sanitizer_flags.cc @@ -30,6 +30,7 @@ ParseFlag(str, &f->handle_ioctl, "handle_ioctl"); ParseFlag(str, &f->log_path, "log_path"); ParseFlag(str, &f->detect_leaks, "detect_leaks"); + ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit"); } static bool GetFlagValue(const char *env, const char *name,