[lsan] Make LSan ignore memory poisoned by ASan.

Summary:
No more (potenital) false negatives due to red zones or fake stack
frames.

Reviewers: kcc, samsonov

Reviewed By: samsonov

CC: llvm-commits, samsonov

Differential Revision: http://llvm-reviews.chandlerc.com/D2359

llvm-svn: 196778
This commit is contained in:
Sergey Matveev 2013-12-09 13:12:10 +00:00
parent 3519dce968
commit b1b8d1aa47
6 changed files with 57 additions and 0 deletions

View File

@ -292,3 +292,11 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
*(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
}
}
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
bool WordIsPoisoned(uptr addr) {
return __asan_region_is_poisoned(addr, sizeof(uptr));
}
}

View File

@ -17,6 +17,8 @@ if not os.path.exists(lsan_lit_cfg):
lit_config.fatal("Can't find common LSan lit config at: %r" % lsan_lit_cfg)
lit_config.load_config(config, lsan_lit_cfg)
config.available_features.add('asan')
config.name = 'LeakSanitizer-AddressSanitizer'
clang_lsan_cxxflags = config.clang_cxxflags + " -fsanitize=address "

View File

@ -0,0 +1,25 @@
// ASan-poisoned memory should be ignored if use_poisoned is false.
// REQUIRES: asan
// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
// RUN: %clangxx_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=0" not %t 2>&1 | FileCheck %s
// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=1" %t 2>&1
#include <stdio.h>
#include <stdlib.h>
#include <sanitizer/asan_interface.h>
#include <assert.h>
void **p;
int main() {
p = new void *;
*p = malloc(1337);
fprintf(stderr, "Test alloc: %p.\n", *p);
__asan_poison_memory_region(p, sizeof(*p));
return 0;
}
// CHECK: Test alloc: [[ADDR:.*]].
// CHECK: Directly leaked 1337 byte object at [[ADDR]]
// CHECK: LeakSanitizer: detected memory leaks
// CHECK: SUMMARY: AddressSanitizer:

View File

@ -35,6 +35,11 @@ static void InitializeCommonFlags() {
ParseCommonFlagsFromString(cf, GetEnv("LSAN_OPTIONS"));
}
///// Interface to the common LSan module. /////
bool WordIsPoisoned(uptr addr) {
return false;
}
} // namespace __lsan
using namespace __lsan; // NOLINT

View File

@ -47,6 +47,7 @@ static void InitializeFlags() {
f->use_stacks = true;
f->use_tls = true;
f->use_unaligned = false;
f->use_poisoned = false;
f->verbosity = 0;
f->log_pointers = false;
f->log_threads = false;
@ -58,6 +59,7 @@ static void InitializeFlags() {
ParseFlag(options, &f->use_stacks, "use_stacks");
ParseFlag(options, &f->use_tls, "use_tls");
ParseFlag(options, &f->use_unaligned, "use_unaligned");
ParseFlag(options, &f->use_poisoned, "use_poisoned");
ParseFlag(options, &f->report_objects, "report_objects");
ParseFlag(options, &f->resolution, "resolution");
CHECK_GE(&f->resolution, 0);
@ -148,6 +150,17 @@ void ScanRangeForPointers(uptr begin, uptr end,
// Reachable beats ignored beats leaked.
if (m.tag() == kReachable) continue;
if (m.tag() == kIgnored && tag != kReachable) continue;
// Do this check relatively late so we can log only the interesting cases.
if (!flags()->use_poisoned && WordIsPoisoned(pp)) {
if (flags()->log_pointers)
Report(
"%p is poisoned: ignoring %p pointing into chunk %p-%p of size "
"%zu.\n",
pp, p, chunk, chunk + m.requested_size(), m.requested_size());
continue;
}
m.set_tag(tag);
if (flags()->log_pointers)
Report("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p,

View File

@ -66,6 +66,8 @@ struct Flags {
// Consider unaligned pointers valid.
bool use_unaligned;
// Consider pointers found in poisoned memory to be valid.
bool use_poisoned;
// User-visible verbosity.
int verbosity;
@ -129,6 +131,8 @@ void GetAllocatorGlobalRange(uptr *begin, uptr *end);
// Wrappers for allocator's ForceLock()/ForceUnlock().
void LockAllocator();
void UnlockAllocator();
// Returns true if [addr, addr + sizeof(void *)) is poisoned.
bool WordIsPoisoned(uptr addr);
// Wrappers for ThreadRegistry access.
void LockThreadRegistry();
void UnlockThreadRegistry();