[compiler-rt] [tsan] Allow unloading of ignored librairies (PR #105660)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 22 06:42:47 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-compiler-rt-sanitizer
Author: None (goussepi)
<details>
<summary>Changes</summary>
Allows unloading and reloading of ignored libraries. We don't attempt to reuse of free memory of unloaded library. So TSan will assert if an ignored library is reloaded 128 times.
---
Full diff: https://github.com/llvm/llvm-project/pull/105660.diff
3 Files Affected:
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp (+11-3)
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_libignore.h (+30-2)
- (modified) compiler-rt/test/tsan/ignore_lib3.cpp (+21-8)
``````````diff
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp
index f0e1e3d69def53..85b97ac0e78a93 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cpp
@@ -33,6 +33,7 @@ void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
lib->name = nullptr;
lib->real_name = nullptr;
lib->loaded = false;
+ lib->ignored_code_range_id = kInvalidCodeRangeId;
}
void LibIgnore::OnLibraryLoaded(const char *name) {
@@ -81,17 +82,24 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
const uptr idx =
atomic_load(&ignored_ranges_count_, memory_order_relaxed);
CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_));
- ignored_code_ranges_[idx].begin = range.beg;
+ ignored_code_ranges_[idx].begin(range.beg);
ignored_code_ranges_[idx].end = range.end;
+ ignored_code_ranges_[idx].loaded = 1;
+ // Record the index of the ignored range.
+ lib->ignored_code_range_id = idx;
atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release);
break;
}
}
if (lib->loaded && !loaded) {
- Report("%s: library '%s' that was matched against called_from_lib"
+ VReport(1, "%s: library '%s' that was matched against called_from_lib"
" suppression '%s' is unloaded\n",
SanitizerToolName, lib->name, lib->templ);
- Die();
+ // The library is unloaded so mark the ignored code range as unloaded.
+ CHECK_NE(lib->ignored_code_range_id, kInvalidCodeRangeId);
+ ignored_code_ranges_[lib->ignored_code_range_id].loaded = 0;
+ lib->ignored_code_range_id = kInvalidCodeRangeId;
+ lib->loaded = false;
}
}
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h
index 18e4d83ed77fb8..228d15b3733cc7 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h
@@ -54,6 +54,7 @@ class LibIgnore {
char *name;
char *real_name; // target of symlink
bool loaded;
+ uptr ignored_code_range_id;
};
struct LibCodeRange {
@@ -61,6 +62,31 @@ class LibIgnore {
uptr end;
};
+ // Marks a range as loaded by utilizing the least significant bit of the code
+ // range. Assumes the start of the code range is 2-byte aligned.
+ struct LibLoadedCodeRange {
+ uptr begin() const { return begin_ << 1; }
+ void begin(uptr begin) {
+ CHECK_EQ(begin & 0x1, 0);
+ begin_ = begin >> 1;
+ }
+
+ private:
+ uptr begin_ : 63;
+
+ public:
+ uptr loaded : 1;
+ uptr end;
+ };
+
+ static_assert(sizeof(LibLoadedCodeRange) == 16,
+ "LibLoadedCodeRange size expected to be 16-bytes for "
+ "performance reasons.");
+
+ inline bool IsInRange(uptr pc, const LibLoadedCodeRange &range) const {
+ return (pc >= range.begin() && pc < range.end);
+ }
+
inline bool IsInRange(uptr pc, const LibCodeRange &range) const {
return (pc >= range.begin && pc < range.end);
}
@@ -68,10 +94,11 @@ class LibIgnore {
static const uptr kMaxIgnoredRanges = 128;
static const uptr kMaxInstrumentedRanges = 1024;
static const uptr kMaxLibs = 1024;
+ static const uptr kInvalidCodeRangeId = ~0x0ULL;
// Hot part:
atomic_uintptr_t ignored_ranges_count_;
- LibCodeRange ignored_code_ranges_[kMaxIgnoredRanges];
+ LibLoadedCodeRange ignored_code_ranges_[kMaxIgnoredRanges];
atomic_uintptr_t instrumented_ranges_count_;
LibCodeRange instrumented_code_ranges_[kMaxInstrumentedRanges];
@@ -90,7 +117,8 @@ class LibIgnore {
inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const {
const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire);
for (uptr i = 0; i < n; i++) {
- if (IsInRange(pc, ignored_code_ranges_[i])) {
+ if (ignored_code_ranges_[i].loaded &&
+ IsInRange(pc, ignored_code_ranges_[i])) {
*pc_in_ignored_lib = true;
return true;
}
diff --git a/compiler-rt/test/tsan/ignore_lib3.cpp b/compiler-rt/test/tsan/ignore_lib3.cpp
index b1a3940d03b615..c1fac0138f68ef 100644
--- a/compiler-rt/test/tsan/ignore_lib3.cpp
+++ b/compiler-rt/test/tsan/ignore_lib3.cpp
@@ -3,10 +3,10 @@
// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %t-dir/libignore_lib3.so
// RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t-dir/executable
-// RUN: %env_tsan_opts=suppressions='%s.supp' %deflake %run %t-dir/executable | FileCheck %s
+// RUN: %env_tsan_opts=suppressions='%s.supp':verbosity=1 %run %t-dir/executable 2>&1 | FileCheck %s
// Tests that unloading of a library matched against called_from_lib suppression
-// causes program crash (this is not supported).
+// is supported.
// Some aarch64 kernels do not support non executable write pages
// REQUIRES: stable-runtime
@@ -22,18 +22,31 @@
int main(int argc, char **argv) {
std::string lib = std::string(dirname(argv[0])) + "/libignore_lib3.so";
- void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
- dlclose(h);
+ void *h;
+ void (*f)();
+ // Try opening, closing and reopening the ignored lib.
+ for (unsigned int k = 0; k < 2; k++) {
+ h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ if (h == 0)
+ exit(printf("failed to load the library (%d)\n", errno));
+ f = (void (*)())dlsym(h, "libfunc");
+ if (f == 0)
+ exit(printf("failed to find the func (%d)\n", errno));
+ f();
+ dlclose(h);
+ }
fprintf(stderr, "OK\n");
}
#else // #ifdef LIB
-extern "C" void libfunc() {
-}
+#include "ignore_lib_lib.h"
#endif // #ifdef LIB
-// CHECK: ThreadSanitizer: library {{.*}} that was matched against called_from_lib suppression 'ignore_lib3.so' is unloaded
-// CHECK-NOT: OK
+// CHECK: Matched called_from_lib suppression 'ignore_lib3.so'
+// CHECK: library '{{.*}}ignore_lib3.so' that was matched against called_from_lib suppression 'ignore_lib3.so' is unloaded
+// CHECK: Matched called_from_lib suppression 'ignore_lib3.so'
+// CHECK: library '{{.*}}ignore_lib3.so' that was matched against called_from_lib suppression 'ignore_lib3.so' is unloaded
+// CHECK: OK
``````````
</details>
https://github.com/llvm/llvm-project/pull/105660
More information about the llvm-commits
mailing list