Skip to content

Commit 655bd0d

Browse files
committed
[lsan] Add __lsan_do_leak_check() to the public interface.
Let users override the normal behavior to run leak checking earlier in the process. Also fix a couple nits here and there. llvm-svn: 186581
1 parent 49c7e22 commit 655bd0d

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

compiler-rt/include/sanitizer/lsan_interface.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,23 @@
2020
extern "C" {
2121
#endif
2222
// Allocations made between calls to __lsan_disable() and __lsan_enable() will
23-
// be treated as non-leaks. Disable/enable pairs can be nested.
23+
// be treated as non-leaks. Disable/enable pairs may be nested.
2424
void __lsan_disable();
2525
void __lsan_enable();
2626
// The heap object into which p points will be treated as a non-leak.
2727
void __lsan_ignore_object(const void *p);
2828
// The user may optionally provide this function to disallow leak checking
29-
// for the program it is linked into. Note: this function may be called late,
30-
// after all the global destructors.
29+
// for the program it is linked into (if the return value is non-zero). This
30+
// function must be defined as returning a constant value; any behavior beyond
31+
// that is unsupported.
3132
int __lsan_is_turned_off();
33+
// Calling this function makes LSan enter the leak checking phase immediately.
34+
// Use this if normal end-of-process leak checking happens too late (e.g. if
35+
// you have intentional memory leaks in your shutdown code). Calling this
36+
// function overrides end-of-process leak checking; it must be called at
37+
// most once per process. This function will terminate the process if there
38+
// are memory leaks and the exit_code flag is non-zero.
39+
void __lsan_do_leak_check();
3240
#ifdef __cplusplus
3341
} // extern "C"
3442

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Test for __lsan_do_leak_check(). We test it by making the leak check run
2+
// before global destructors, which also tests compatibility with HeapChecker's
3+
// "normal" mode (LSan runs in "strict" mode by default).
4+
// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
5+
// RUN: %clangxx_lsan %s -o %t
6+
// RUN: LSAN_OPTIONS=$LSAN_BASE %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s
7+
// RUN: LSAN_OPTIONS=$LSAN_BASE %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s
8+
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <sanitizer/lsan_interface.h>
12+
13+
struct LeakyGlobal {
14+
LeakyGlobal() {
15+
p = malloc(1337);
16+
}
17+
~LeakyGlobal() {
18+
p = 0;
19+
}
20+
void *p;
21+
};
22+
23+
LeakyGlobal leaky_global;
24+
25+
int main(int argc, char *argv[]) {
26+
// Register leak check to run before global destructors.
27+
if (argc > 1)
28+
atexit(&__lsan_do_leak_check);
29+
void *p = malloc(666);
30+
printf("Test alloc: %p\n", p);
31+
printf("Test alloc in leaky global: %p\n", leaky_global.p);
32+
return 0;
33+
}
34+
35+
// CHECK-strict: SUMMARY: LeakSanitizer: 2003 byte(s) leaked in 2 allocation(s)
36+
// CHECK-normal: SUMMARY: LeakSanitizer: 666 byte(s) leaked in 1 allocation(s)

compiler-rt/lib/lsan/lsan_common.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ void ScanRangeForPointers(uptr begin, uptr end,
125125
if (pp % alignment)
126126
pp = pp + alignment - pp % alignment;
127127
for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT
128-
void *p = *reinterpret_cast<void**>(pp);
128+
void *p = *reinterpret_cast<void **>(pp);
129129
if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
130130
uptr chunk = PointsIntoChunk(p);
131131
if (!chunk) continue;
@@ -353,7 +353,7 @@ void DoLeakCheck() {
353353
EnsureMainThreadIDIsCorrect();
354354
BlockingMutexLock l(&global_mutex);
355355
static bool already_done;
356-
CHECK(!already_done);
356+
if (already_done) return;
357357
already_done = true;
358358
if (&__lsan_is_turned_off && __lsan_is_turned_off())
359359
return;
@@ -544,6 +544,13 @@ void __lsan_enable() {
544544
#endif
545545
}
546546

547+
SANITIZER_INTERFACE_ATTRIBUTE
548+
void __lsan_do_leak_check() {
549+
#if CAN_SANITIZE_LEAKS
550+
__lsan::DoLeakCheck();
551+
#endif
552+
}
553+
547554
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
548555
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
549556
int __lsan_is_turned_off() {

0 commit comments

Comments
 (0)