[LSan] Detect dynamic loader by its base address.
authorAlex Shlyapnikov <alekseys@google.com>
Mon, 6 Nov 2017 21:27:06 +0000 (21:27 +0000)
committerAlex Shlyapnikov <alekseys@google.com>
Mon, 6 Nov 2017 21:27:06 +0000 (21:27 +0000)
Summary:
Relanding D38600, which was reverted due to various PPC bot failures.

If it breaks something again, please provide some pointers to broken
bots, not just revert it, otherwise it's very hard to reason what's
wrong with this commit.

Whenever possible (Linux + glibc 2.16+), detect dynamic loader module by
its base address, not by the module name matching. The current name
matching approach fails on some configurations.

Reviewers: eugenis

Subscribers: kubamracek, llvm-commits

Differential Revision: https://reviews.llvm.org/D39275

llvm-svn: 317512

compiler-rt/lib/lsan/lsan_common.cc
compiler-rt/lib/lsan/lsan_common_linux.cc
compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h [new file with mode: 0644]
compiler-rt/lib/sanitizer_common/sanitizer_linux.cc

index 622aae7..651bbe1 100644 (file)
@@ -411,8 +411,9 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) {
   }
 }
 
-// On Linux, handles dynamically allocated TLS blocks by treating all chunks
-// allocated from ld-linux.so as reachable.
+// On Linux, treats all chunks allocated from ld-linux.so as reachable, which
+// covers dynamically allocated TLS blocks, internal dynamic loader's loaded
+// modules accounting etc.
 // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
 // They are allocated with a __libc_memalign() call in allocate_and_init()
 // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
index 5042c7b..cdd7f03 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_getauxval.h"
 #include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 
@@ -30,8 +31,12 @@ static const char kLinkerName[] = "ld";
 static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
 static LoadedModule *linker = nullptr;
 
-static bool IsLinker(const char* full_name) {
-  return LibraryNameIs(full_name, kLinkerName);
+static bool IsLinker(const LoadedModule& module) {
+#if SANITIZER_USE_GETAUXVAL
+  return module.base_address() == getauxval(AT_BASE);
+#else
+  return LibraryNameIs(module.full_name(), kLinkerName);
+#endif  // SANITIZER_USE_GETAUXVAL
 }
 
 __attribute__((tls_model("initial-exec")))
@@ -49,22 +54,25 @@ void InitializePlatformSpecificModules() {
   ListOfModules modules;
   modules.init();
   for (LoadedModule &module : modules) {
-    if (!IsLinker(module.full_name())) continue;
+    if (!IsLinker(module))
+      continue;
     if (linker == nullptr) {
       linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
       *linker = module;
       module = LoadedModule();
     } else {
       VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
-              "TLS will not be handled correctly.\n", kLinkerName);
+              "TLS and other allocations originating from linker might be "
+              "falsely reported as leaks.\n", kLinkerName);
       linker->clear();
       linker = nullptr;
       return;
     }
   }
   if (linker == nullptr) {
-    VReport(1, "LeakSanitizer: Dynamic linker not found. "
-               "TLS will not be handled correctly.\n");
+    VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
+               "allocations originating from linker might be falsely reported "
+                "as leaks.\n");
   }
 }
 
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h b/compiler-rt/lib/sanitizer_common/sanitizer_getauxval.h
new file mode 100644 (file)
index 0000000..d0287f0
--- /dev/null
@@ -0,0 +1,40 @@
+//===-- sanitizer_getauxval.h -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common getauxval() guards and definitions.
+// getauxval() is not defined until glbc version 2.16.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_GETAUXVAL_H
+#define SANITIZER_GETAUXVAL_H
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_LINUX
+
+#include <features.h>
+
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(x, y) 0
+#endif
+
+#if __GLIBC_PREREQ(2, 16)
+# define SANITIZER_USE_GETAUXVAL 1
+#else
+# define SANITIZER_USE_GETAUXVAL 0
+#endif
+
+#if SANITIZER_USE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+
+#endif // SANITIZER_LINUX
+
+#endif // SANITIZER_GETAUXVAL_H
index 6ea1858..5199aa6 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
+#include "sanitizer_getauxval.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_linux.h"
@@ -95,20 +96,6 @@ extern struct ps_strings *__ps_strings;
 #include <sys/signal.h>
 #endif
 
-#ifndef __GLIBC_PREREQ
-#define __GLIBC_PREREQ(x, y) 0
-#endif
-
-#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16)
-# define SANITIZER_USE_GETAUXVAL 1
-#else
-# define SANITIZER_USE_GETAUXVAL 0
-#endif
-
-#if SANITIZER_USE_GETAUXVAL
-#include <sys/auxv.h>
-#endif
-
 #if SANITIZER_LINUX
 // <linux/time.h>
 struct kernel_timeval {