[UBSan] Embed UBSan into ASan runtime (compiler-rt part).
Summary:
Change the way we use ASan and UBSan together. Instead of keeping two
separate runtimes (libclang_rt.asan and libclang_rt.ubsan), embed UBSan
into ASan and get rid of libclang_rt.ubsan. If UBSan is not supported on
a platform, all UBSan sources are just compiled into dummy empty object
files. UBSan initialization code (e.g. flag parsing) is directly called
from ASan initialization, so we are able to enforce correct
initialization order.
This mirrors the approach we already use for ASan+LSan. This change
doesn't modify the way we use standalone UBSan.
Test Plan: regression test suite
Reviewers: kubabrecka, zaks.anna, rsmith, kcc
Subscribers: llvm-commits
Differential Revision: http://reviews.llvm.org/D8646
llvm-svn: 233861
diff --git a/compiler-rt/lib/ubsan/ubsan_init.cc b/compiler-rt/lib/ubsan/ubsan_init.cc
index 9527269..c3b8b6c 100644
--- a/compiler-rt/lib/ubsan/ubsan_init.cc
+++ b/compiler-rt/lib/ubsan/ubsan_init.cc
@@ -23,45 +23,54 @@
using namespace __ubsan;
-static bool ubsan_inited;
+static enum {
+ UBSAN_MODE_UNKNOWN = 0,
+ UBSAN_MODE_STANDALONE,
+ UBSAN_MODE_PLUGIN
+} ubsan_mode;
+static StaticSpinMutex ubsan_init_mu;
-void __ubsan::InitIfNecessary() {
-#if !SANITIZER_CAN_USE_PREINIT_ARRAY
- // No need to lock mutex if we're initializing from preinit array.
- static StaticSpinMutex init_mu;
- SpinMutexLock l(&init_mu);
-#endif
- if (LIKELY(ubsan_inited))
- return;
- bool standalone = false;
- if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
- // WARNING: If this condition holds, then either UBSan runs in a standalone
- // mode, or initializer for another sanitizer hasn't run yet. In a latter
- // case, another sanitizer will overwrite "SanitizerToolName" and reparse
- // common flags. It means, that we are not allowed to *use* common flags
- // in this function.
- SanitizerToolName = "UndefinedBehaviorSanitizer";
- standalone = true;
- }
- // Initialize UBSan-specific flags.
- InitializeFlags(standalone);
+static void CommonInit() {
InitializeSuppressions();
- InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
- ubsan_inited = true;
}
-#if SANITIZER_CAN_USE_PREINIT_ARRAY
-__attribute__((section(".preinit_array"), used))
-void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary;
-#else
-// Use a dynamic initializer.
-class UbsanInitializer {
- public:
- UbsanInitializer() {
- InitIfNecessary();
+static void CommonStandaloneInit() {
+ SanitizerToolName = "UndefinedBehaviorSanitizer";
+ InitializeFlags();
+ InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+ CommonInit();
+ ubsan_mode = UBSAN_MODE_STANDALONE;
+}
+
+void __ubsan::InitAsStandalone() {
+ if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
+ CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ CommonStandaloneInit();
+ return;
}
-};
-static UbsanInitializer ubsan_initializer;
-#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
+ SpinMutexLock l(&ubsan_init_mu);
+ CHECK_NE(UBSAN_MODE_PLUGIN, ubsan_mode);
+ if (ubsan_mode == UBSAN_MODE_UNKNOWN)
+ CommonStandaloneInit();
+}
+
+void __ubsan::InitAsStandaloneIfNecessary() {
+ if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
+ CHECK_NE(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ return;
+ }
+ SpinMutexLock l(&ubsan_init_mu);
+ if (ubsan_mode == UBSAN_MODE_UNKNOWN)
+ CommonStandaloneInit();
+}
+
+void __ubsan::InitAsPlugin() {
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+ SpinMutexLock l(&ubsan_init_mu);
+#endif
+ CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ CommonInit();
+ ubsan_mode = UBSAN_MODE_PLUGIN;
+}
#endif // CAN_SANITIZE_UB