summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Ostapenko <m.ostapenko@samsung.com>2016-10-05 17:04:08 +0300
committerMaxim Ostapenko <m.ostapenko@samsung.com>2016-11-30 15:00:36 +0300
commit059d7696a8c6ab63d1bf4271a20629e76fcd392e (patch)
tree444084d61ed04d11fd700402ddba5485ee946be5
parent9c2785c174d07a35414709ebde53b1c30e1d139a (diff)
downloadlinaro-gcc-059d7696a8c6ab63d1bf4271a20629e76fcd392e.tar.gz
linaro-gcc-059d7696a8c6ab63d1bf4271a20629e76fcd392e.tar.bz2
linaro-gcc-059d7696a8c6ab63d1bf4271a20629e76fcd392e.zip
Some allocators may use mmap for their local pools that may cause false positive reports because LSan currently doesn't intercept mmap call mainly due to its complexity (we don't know whether a particular mmap would contain live pointers). However for some cases (e.g. anonymous rw mmaps) we can guess that they would contain live pointers thus we can add them into root regions. Thus, now we intercept mmap/munmap calls, add anonymous rw mappings into root regions and call real mmap. Change-Id: Ie0bde91497a31ab670f15d67b34d328969dc0981 Signed-off-by: Maxim Ostapenko <m.ostapenko@samsung.com>
-rw-r--r--libsanitizer/lsan/lsan.cc1
-rw-r--r--libsanitizer/lsan/lsan.h1
-rw-r--r--libsanitizer/lsan/lsan_common.cc10
-rw-r--r--libsanitizer/lsan/lsan_interceptors.cc53
4 files changed, 61 insertions, 4 deletions
diff --git a/libsanitizer/lsan/lsan.cc b/libsanitizer/lsan/lsan.cc
index 33051cef1d5..c8ea483d676 100644
--- a/libsanitizer/lsan/lsan.cc
+++ b/libsanitizer/lsan/lsan.cc
@@ -22,6 +22,7 @@
bool lsan_inited;
bool lsan_init_is_running;
+bool lsan_check_in_progress;
namespace __lsan {
diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
index 30f06ca40bf..ff7c291fc6d 100644
--- a/libsanitizer/lsan/lsan.h
+++ b/libsanitizer/lsan/lsan.h
@@ -49,5 +49,6 @@ void InitializeInterceptors();
extern bool lsan_inited;
extern bool lsan_init_is_running;
+extern bool lsan_check_in_progress;
extern "C" void __lsan_init();
diff --git a/libsanitizer/lsan/lsan_common.cc b/libsanitizer/lsan/lsan_common.cc
index 668e2f4d5e9..23408508ecf 100644
--- a/libsanitizer/lsan/lsan_common.cc
+++ b/libsanitizer/lsan/lsan_common.cc
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "lsan.h"
#include "lsan_common.h"
#include "sanitizer_common/sanitizer_common.h"
@@ -410,6 +411,7 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
static bool CheckForLeaks() {
if (&__lsan_is_turned_off && __lsan_is_turned_off())
return false;
+ lsan_check_in_progress = true;
EnsureMainThreadIDIsCorrect();
CheckForLeaksParam param;
param.success = false;
@@ -441,8 +443,10 @@ static bool CheckForLeaks() {
param.leak_report.PrintSummary();
if (common_flags()->print_cmdline)
PrintCmdline();
+ lsan_check_in_progress = false;
return true;
}
+ lsan_check_in_progress = false;
return false;
}
@@ -651,7 +655,6 @@ void __lsan_ignore_object(const void *p) {
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_register_root_region(const void *begin, uptr size) {
#if CAN_SANITIZE_LEAKS
- BlockingMutexLock l(&global_mutex);
CHECK(root_regions);
RootRegion region = {begin, size};
root_regions->push_back(region);
@@ -662,7 +665,6 @@ void __lsan_register_root_region(const void *begin, uptr size) {
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_unregister_root_region(const void *begin, uptr size) {
#if CAN_SANITIZE_LEAKS
- BlockingMutexLock l(&global_mutex);
CHECK(root_regions);
bool removed = false;
for (uptr i = 0; i < root_regions->size(); i++) {
@@ -677,11 +679,11 @@ void __lsan_unregister_root_region(const void *begin, uptr size) {
}
}
if (!removed) {
- Report(
+ VReport(1,
"__lsan_unregister_root_region(): region at %p of size %llu has not "
"been registered.\n",
begin, size);
- Die();
+ // Do nothing
}
#endif // CAN_SANITIZE_LEAKS
}
diff --git a/libsanitizer/lsan/lsan_interceptors.cc b/libsanitizer/lsan/lsan_interceptors.cc
index 8edd0e0b84c..af0cba975cd 100644
--- a/libsanitizer/lsan/lsan_interceptors.cc
+++ b/libsanitizer/lsan/lsan_interceptors.cc
@@ -18,10 +18,12 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_procmaps.h"
#include "lsan.h"
#include "lsan_allocator.h"
#include "lsan_thread.h"
#include <stddef.h>
+#include <sys/mman.h>
using namespace __lsan;
@@ -31,8 +33,12 @@ int pthread_attr_destroy(void *attr);
int pthread_attr_getdetachstate(void *attr, int *v);
int pthread_key_create(unsigned *key, void (*destructor)(void* v));
int pthread_setspecific(unsigned key, const void *v);
+void __lsan_register_root_region(const void *p, size_t size);
+void __lsan_unregister_root_region(const void *p, size_t size);
}
+BlockingMutex mmap_mutex(LINKER_INITIALIZED);
+
#define ENSURE_LSAN_INITED do { \
CHECK(!lsan_init_is_running); \
if (!lsan_inited) \
@@ -258,6 +264,50 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) {
return res;
}
+static inline bool isSharedMmap(void *addr, int flags) {
+ return (flags & MAP_SHARED) && (addr == NULL);
+}
+
+static inline bool isAnonymousMmap(int flags, int fd) {
+ return ((flags & MAP_ANON) || (flags & MAP_ANONYMOUS)) &&
+ !(flags & MAP_STACK) && (fd == -1);
+}
+
+static inline bool isInterestingMmap(void *addr, int prot, int flags, int fd) {
+ return ((prot & PROT_WRITE) && (prot & PROT_READ)) &&
+ (isAnonymousMmap(flags, fd) || isSharedMmap(addr, flags));
+}
+
+static inline void MaybeRegisterMmapRegion(void *res, size_t length, void *addr,
+ int prot, int flags, int fd) {
+ if (!lsan_check_in_progress && isInterestingMmap(addr, prot, flags, fd)) {
+ BlockingMutexLock l(&mmap_mutex);
+ __lsan_register_root_region(res, length);
+ }
+}
+
+INTERCEPTOR(void *, mmap, void *addr, size_t length, int prot, int flags,
+ int fd, off_t offset) {
+ void *res = REAL(mmap)(addr, length, prot, flags, fd, offset);
+ MaybeRegisterMmapRegion(res, length, addr, prot, flags, fd);
+ return res;
+}
+
+INTERCEPTOR(void *, mmap64, void *addr, size_t length, int prot, int flags,
+ int fd, __off64_t offset) {
+ void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset);
+ MaybeRegisterMmapRegion(res, length, addr, prot, flags, fd);
+ return res;
+}
+
+INTERCEPTOR(int, munmap, void *addr, size_t length) {
+ if (!lsan_check_in_progress) {
+ BlockingMutexLock l(&mmap_mutex);
+ __lsan_unregister_root_region(addr, length);
+ }
+ return REAL(munmap)(addr, length);
+}
+
namespace __lsan {
void InitializeInterceptors() {
@@ -276,6 +326,9 @@ void InitializeInterceptors() {
INTERCEPT_FUNCTION(mallopt);
INTERCEPT_FUNCTION(pthread_create);
INTERCEPT_FUNCTION(pthread_join);
+ INTERCEPT_FUNCTION(mmap);
+ INTERCEPT_FUNCTION(mmap64);
+ INTERCEPT_FUNCTION(munmap);
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
Report("LeakSanitizer: failed to create thread key.\n");