[PATCH] [lsan] Add __lsan_do_leak_check() to the public interface.

Sergey Matveev earthdok at google.com
Thu Jul 18 06:52:15 PDT 2013


Hi samsonov,

Let the user override normal behavior to run leak checking earlier in
the process. Also fix a couple nits here and there.

http://llvm-reviews.chandlerc.com/D1176

Files:
  include/sanitizer/lsan_interface.h
  lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
  lib/lsan/lsan_common.cc

Index: include/sanitizer/lsan_interface.h
===================================================================
--- include/sanitizer/lsan_interface.h
+++ include/sanitizer/lsan_interface.h
@@ -20,15 +20,23 @@
 extern "C" {
 #endif
   // Allocations made between calls to __lsan_disable() and __lsan_enable() will
-  // be treated as non-leaks. Disable/enable pairs can be nested.
+  // be treated as non-leaks. Disable/enable pairs may be nested.
   void __lsan_disable();
   void __lsan_enable();
   // The heap object into which p points will be treated as a non-leak.
   void __lsan_ignore_object(const void *p);
   // The user may optionally provide this function to disallow leak checking
-  // for the program it is linked into. Note: this function may be called late,
-  // after all the global destructors.
+  // for the program it is linked into (if the return value is non-zero). This
+  // function must be defined as returning a constant value; any behavior beyond
+  // that is unsupported.
   int __lsan_is_turned_off();
+  // Calling this function makes LSan enter the leak checking phase immediately.
+  // Use this if normal end-of-process leak checking happens too late (e.g. if
+  // you have intentional memory leaks in your shutdown code). Calling this
+  // function overrides end-of-process leak checking; it must be called at
+  // most once per process. This function will terminate the process if there
+  // are memory leaks and the exit_code flag is non-zero. 
+  void __lsan_do_leak_check();
 #ifdef __cplusplus
 }  // extern "C"
 
Index: lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
===================================================================
--- /dev/null
+++ lib/lsan/lit_tests/TestCases/do_leak_check_override.cc
@@ -0,0 +1,36 @@
+// Test for __lsan_do_leak_check(). We test it by making the leak check run
+// before global destructors, which also tests compatibility with HeapChecker's
+// "normal" mode (LSan runs in "strict" mode by default).
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sanitizer/lsan_interface.h>
+
+struct LeakyGlobal {
+  LeakyGlobal() {
+    p = malloc(1337);
+  }
+  ~LeakyGlobal() {
+    p = 0;
+  }
+  void *p;
+};
+
+LeakyGlobal leaky_global;
+
+int main(int argc, char *argv[]) {
+  // Register leak check to run before global destructors.
+  if (argc > 1)
+    atexit(&__lsan_do_leak_check);
+  void *p = malloc(666);
+  printf("Test alloc: %p\n", p);
+  printf("Test alloc in leaky global: %p\n", leaky_global.p);
+  return 0;
+}
+
+// CHECK-strict: SUMMARY: LeakSanitizer: 2003 byte(s) leaked in 2 allocation(s)
+// CHECK-normal: SUMMARY: LeakSanitizer: 666 byte(s) leaked in 1 allocation(s)
Index: lib/lsan/lsan_common.cc
===================================================================
--- lib/lsan/lsan_common.cc
+++ lib/lsan/lsan_common.cc
@@ -125,7 +125,7 @@
   if (pp % alignment)
     pp = pp + alignment - pp % alignment;
   for (; pp + sizeof(void *) <= end; pp += alignment) {  // NOLINT
-    void *p = *reinterpret_cast<void**>(pp);
+    void *p = *reinterpret_cast<void **>(pp);
     if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
     uptr chunk = PointsIntoChunk(p);
     if (!chunk) continue;
@@ -353,7 +353,7 @@
   EnsureMainThreadIDIsCorrect();
   BlockingMutexLock l(&global_mutex);
   static bool already_done;
-  CHECK(!already_done);
+  if (already_done) return;
   already_done = true;
   if (&__lsan_is_turned_off && __lsan_is_turned_off())
     return;
@@ -544,6 +544,13 @@
 #endif
 }
 
+SANITIZER_INTERFACE_ATTRIBUTE
+void __lsan_do_leak_check() {
+#if CAN_SANITIZE_LEAKS
+  __lsan::DoLeakCheck();
+#endif
+}
+
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
 int __lsan_is_turned_off() {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D1176.1.patch
Type: text/x-patch
Size: 4022 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130718/11b54c81/attachment.bin>


More information about the llvm-commits mailing list