summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib/sanitizer_common
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2013-10-03 13:37:17 +0000
committerDmitry Vyukov <dvyukov@google.com>2013-10-03 13:37:17 +0000
commit5ba736457c94580b9cf8a0a65fccf9a89da0b1a6 (patch)
treeafa352b57a63c0e8b42932077375b7c6310a3515 /compiler-rt/lib/sanitizer_common
parentd2757ba1be2915c8f41dd850ffdda8ff6a673382 (diff)
downloadbcm5719-llvm-5ba736457c94580b9cf8a0a65fccf9a89da0b1a6.tar.gz
bcm5719-llvm-5ba736457c94580b9cf8a0a65fccf9a89da0b1a6.zip
tsan: ignore interceptors coming from specified libraries
LibIgnore allows to ignore all interceptors called from a particular set of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions from the provided SuppressionContext; finds code ranges for the libraries; and checks whether the provided PC value belongs to the code ranges. Also make malloc and friends interceptors use SCOPED_INTERCEPTOR_RAW instead of SCOPED_TSAN_INTERCEPTOR, because if they are called from an ignored lib, then must call our internal allocator instead of libc malloc. llvm-svn: 191897
Diffstat (limited to 'compiler-rt/lib/sanitizer_common')
-rw-r--r--compiler-rt/lib/sanitizer_common/CMakeLists.txt2
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc85
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_libignore.h83
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc9
-rw-r--r--compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h5
-rw-r--r--compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc4
6 files changed, 183 insertions, 5 deletions
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 63c49630c13..6a960c9257b 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -6,6 +6,7 @@ set(SANITIZER_SOURCES
sanitizer_common.cc
sanitizer_flags.cc
sanitizer_libc.cc
+ sanitizer_libignore.cc
sanitizer_linux.cc
sanitizer_mac.cc
sanitizer_platform_limits_linux.cc
@@ -44,6 +45,7 @@ set(SANITIZER_HEADERS
sanitizer_internal_defs.h
sanitizer_lfstack.h
sanitizer_libc.h
+ sanitizer_libignore.h
sanitizer_linux.h
sanitizer_list.h
sanitizer_mutex.h
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc
new file mode 100644
index 00000000000..9a0213e7b2b
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc
@@ -0,0 +1,85 @@
+//===-- sanitizer_libignore.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_libignore.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+LibIgnore::LibIgnore(LinkerInitialized) {
+}
+
+void LibIgnore::Init(const SuppressionContext &supp) {
+ BlockingMutexLock lock(&mutex_);
+ CHECK_EQ(count_, 0);
+ const uptr n = supp.SuppressionCount();
+ for (uptr i = 0; i < n; i++) {
+ const Suppression *s = supp.SuppressionAt(i);
+ if (s->type != SuppressionLib)
+ continue;
+ if (count_ >= kMaxLibs) {
+ Report("%s: too many called_from_lib suppressions (max: %d)\n",
+ SanitizerToolName, kMaxLibs);
+ Die();
+ }
+ Lib *lib = &libs_[count_++];
+ lib->templ = internal_strdup(s->templ);
+ lib->name = 0;
+ lib->loaded = false;
+ }
+}
+
+void LibIgnore::OnLibraryLoaded() {
+ BlockingMutexLock lock(&mutex_);
+ MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+ InternalScopedBuffer<char> fn(4096);
+ for (uptr i = 0; i < count_; i++) {
+ Lib *lib = &libs_[i];
+ bool loaded = false;
+ proc_maps.Reset();
+ uptr b, e, off, prot;
+ while (proc_maps.Next(&b, &e, &off, fn.data(), fn.size(), &prot)) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) != 0 &&
+ TemplateMatch(lib->templ, fn.data())) {
+ if (loaded) {
+ Report("%s: called_from_lib suppression '%s' is matched against"
+ " 2 libraries: '%s' and '%s'\n",
+ SanitizerToolName, lib->templ, lib->name, fn.data());
+ Die();
+ }
+ loaded = true;
+ if (!lib->loaded) {
+ lib->loaded = true;
+ lib->name = internal_strdup(fn.data());
+ const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
+ code_ranges_[idx].begin = b;
+ code_ranges_[idx].end = e;
+ atomic_store(&loaded_count_, idx + 1, memory_order_release);
+ }
+ }
+ }
+ if (lib->loaded && !loaded) {
+ Report("%s: library '%s' that was matched against called_from_lib"
+ " suppression '%s' is unloaded\n",
+ SanitizerToolName, lib->name, lib->templ);
+ Die();
+ }
+ }
+}
+
+void LibIgnore::OnLibraryUnloaded() {
+ OnLibraryLoaded();
+}
+
+} // namespace __sanitizer
+
+#endif // #if SANITIZER_LINUX
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h
new file mode 100644
index 00000000000..4e6f5a97ada
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h
@@ -0,0 +1,83 @@
+//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LibIgnore allows to ignore all interceptors called from a particular set
+// of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions
+// from the provided SuppressionContext; finds code ranges for the libraries;
+// and checks whether the provided PC value belongs to the code ranges.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_LIBIGNORE_H
+#define SANITIZER_LIBIGNORE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_suppressions.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+class LibIgnore {
+ public:
+ explicit LibIgnore(LinkerInitialized);
+
+ // Fetches all "called_from_lib" suppressions from the SuppressionContext.
+ void Init(const SuppressionContext &supp);
+
+ // Must be called after a new dynamic library is loaded.
+ void OnLibraryLoaded();
+
+ // Must be called after a dynamic library is unloaded.
+ void OnLibraryUnloaded();
+
+ // Checks whether the provided PC belongs to one of the ignored libraries.
+ bool IsIgnored(uptr pc) const;
+
+ private:
+ struct Lib {
+ char *templ;
+ char *name;
+ bool loaded;
+ };
+
+ struct LibCodeRange {
+ uptr begin;
+ uptr end;
+ };
+
+ static const uptr kMaxLibs = 128;
+
+ // Hot part:
+ atomic_uintptr_t loaded_count_;
+ LibCodeRange code_ranges_[kMaxLibs];
+
+ // Cold part:
+ BlockingMutex mutex_;
+ uptr count_;
+ Lib libs_[kMaxLibs];
+
+ // Disallow copying of LibIgnore objects.
+ LibIgnore(const LibIgnore&); // not implemented
+ void operator = (const LibIgnore&); // not implemented
+};
+
+inline bool LibIgnore::IsIgnored(uptr pc) const {
+ const uptr n = atomic_load(&loaded_count_, memory_order_acquire);
+ for (uptr i = 0; i < n; i++) {
+ if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end)
+ return true;
+ }
+ return false;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIBIGNORE_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc b/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
index 0676c0bd80a..5f3d2cee8ce 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -20,7 +20,7 @@
namespace __sanitizer {
static const char *const kTypeStrings[SuppressionTypeCount] = {
- "none", "race", "mutex", "thread", "signal", "leak"
+ "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
};
bool TemplateMatch(char *templ, const char *str) {
@@ -129,10 +129,15 @@ void SuppressionContext::Parse(const char *str) {
}
}
-uptr SuppressionContext::SuppressionCount() {
+uptr SuppressionContext::SuppressionCount() const {
return suppressions_.size();
}
+const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
+ CHECK_LT(i, suppressions_.size());
+ return &suppressions_[i];
+}
+
void SuppressionContext::GetMatched(
InternalMmapVector<Suppression *> *matched) {
for (uptr i = 0; i < suppressions_.size(); i++)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h b/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
index e0b562e5825..92cb09365b5 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h
@@ -25,6 +25,7 @@ enum SuppressionType {
SuppressionThread,
SuppressionSignal,
SuppressionLeak,
+ SuppressionLib,
SuppressionTypeCount
};
@@ -40,7 +41,8 @@ class SuppressionContext {
SuppressionContext() : suppressions_(1), can_parse_(true) {}
void Parse(const char *str);
bool Match(const char* str, SuppressionType type, Suppression **s);
- uptr SuppressionCount();
+ uptr SuppressionCount() const;
+ const Suppression *SuppressionAt(uptr i) const;
void GetMatched(InternalMmapVector<Suppression *> *matched);
private:
@@ -52,7 +54,6 @@ class SuppressionContext {
const char *SuppressionTypeString(SuppressionType t);
-// Exposed for testing.
bool TemplateMatch(char *templ, const char *str);
} // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
index f44911e1b98..ea8741d4f01 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -65,8 +65,10 @@ TEST(Suppressions, TypeStrings) {
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread"));
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
+ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
+ "called_from_lib"));
// Ensure this test is up-to-date when suppression types are added.
- CHECK_EQ(SuppressionTypeCount, 6);
+ CHECK_EQ(SuppressionTypeCount, 7);
}
class SuppressionContextTest : public ::testing::Test {
OpenPOWER on IntegriCloud