diff options
author | Vitaly Buka <vitalybuka@google.com> | 2024-08-02 14:13:21 -0700 |
---|---|---|
committer | Vitaly Buka <vitalybuka@google.com> | 2024-08-02 14:13:21 -0700 |
commit | 104b66ec50d4b251b088e71402ad86d2bec49811 (patch) | |
tree | fe8f12f56deab6cbe9e7ea42d2699a20e97b1a1e | |
parent | 72a514f42722ad6f6e6baee8e2d75150f9369a66 (diff) | |
download | llvm-users/vitalybuka/spr/main.nfcmoduleutils-test-appendtoglobalctorsappendtoglobaldtors.zip llvm-users/vitalybuka/spr/main.nfcmoduleutils-test-appendtoglobalctorsappendtoglobaldtors.tar.gz llvm-users/vitalybuka/spr/main.nfcmoduleutils-test-appendtoglobalctorsappendtoglobaldtors.tar.bz2 |
[𝘀𝗽𝗿] changes to main this commit is based onusers/vitalybuka/spr/main.nfcmoduleutils-test-appendtoglobalctorsappendtoglobaldtors
Created using spr 1.3.4
[skip ci]
-rw-r--r-- | compiler-rt/lib/asan/asan_globals.cpp | 130 | ||||
-rw-r--r-- | llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp | 5 | ||||
-rw-r--r-- | llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp | 26 |
3 files changed, 121 insertions, 40 deletions
diff --git a/compiler-rt/lib/asan/asan_globals.cpp b/compiler-rt/lib/asan/asan_globals.cpp index cc5308a..80030af 100644 --- a/compiler-rt/lib/asan/asan_globals.cpp +++ b/compiler-rt/lib/asan/asan_globals.cpp @@ -47,8 +47,6 @@ struct DynInitGlobal { bool initialized = false; DynInitGlobal *next = nullptr; }; -typedef IntrusiveList<DynInitGlobal> DynInitGlobals; -static DynInitGlobals dynamic_init_globals SANITIZER_GUARDED_BY(mu_for_globals); // We want to remember where a certain range of globals was registered. struct GlobalRegistrationSite { @@ -72,6 +70,25 @@ static ListOfGlobals &GlobalsByIndicator(uptr odr_indicator) return (*globals_by_indicator)[odr_indicator]; } +static const char *current_dynamic_init_module_name + SANITIZER_GUARDED_BY(mu_for_globals) = nullptr; + +using DynInitGlobalsByModule = + DenseMap<const char *, IntrusiveList<DynInitGlobal>>; + +// TODO: Add a NoDestroy helper, this patter is very common in sanitizers. +static DynInitGlobalsByModule &DynInitGlobals() + SANITIZER_REQUIRES(mu_for_globals) { + static DynInitGlobalsByModule *globals_by_module = nullptr; + if (!globals_by_module) { + alignas(alignof(DynInitGlobalsByModule)) static char + placeholder[sizeof(DynInitGlobalsByModule)]; + globals_by_module = new (placeholder) DynInitGlobalsByModule(); + } + + return *globals_by_module; +} + ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) { FastPoisonShadow(g->beg, g->size_with_redzone, value); } @@ -257,8 +274,8 @@ static void RegisterGlobal(const Global *g) SANITIZER_REQUIRES(mu_for_globals) { AddGlobalToList(list_of_all_globals, g); if (g->has_dynamic_init) { - dynamic_init_globals.push_back(new (GetGlobalLowLevelAllocator()) - DynInitGlobal{*g, false}); + DynInitGlobals()[g->module_name].push_back( + new (GetGlobalLowLevelAllocator()) DynInitGlobal{*g, false}); } } @@ -284,20 +301,42 @@ static void UnregisterGlobal(const Global *g) } } -void StopInitOrderChecking() { - if (!flags()->check_initialization_order) - return; - Lock lock(&mu_for_globals); - flags()->check_initialization_order = false; - for (const DynInitGlobal &dyn_g : dynamic_init_globals) { +static void UnpoisonDynamicGlobals(IntrusiveList<DynInitGlobal> &dyn_globals, + bool mark_initialized) { + for (auto &dyn_g : dyn_globals) { const Global *g = &dyn_g.g; + if (dyn_g.initialized) + continue; // Unpoison the whole global. PoisonShadowForGlobal(g, 0); // Poison redzones back. PoisonRedZones(*g); + if (mark_initialized) + dyn_g.initialized = true; } } +static void PoisonDynamicGlobals( + const IntrusiveList<DynInitGlobal> &dyn_globals) { + for (auto &dyn_g : dyn_globals) { + const Global *g = &dyn_g.g; + if (dyn_g.initialized) + continue; + PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); + } +} + +void StopInitOrderChecking() { + if (!flags()->check_initialization_order) + return; + Lock lock(&mu_for_globals); + flags()->check_initialization_order = false; + DynInitGlobals().forEach([&](auto &kv) { + UnpoisonDynamicGlobals(kv.second, /*mark_initialized=*/false); + return true; + }); +} + static bool IsASCII(unsigned char c) { return /*0x00 <= c &&*/ c <= 0x7F; } const char *MaybeDemangleGlobalName(const char *name) { @@ -456,36 +495,73 @@ void __asan_before_dynamic_init(const char *module_name) { CHECK(module_name); CHECK(AsanInited()); Lock lock(&mu_for_globals); + if (current_dynamic_init_module_name == module_name) + return; if (flags()->report_globals >= 3) Printf("DynInitPoison module: %s\n", module_name); - for (DynInitGlobal &dyn_g : dynamic_init_globals) { - const Global *g = &dyn_g.g; - if (dyn_g.initialized) - continue; - if (g->module_name != module_name) - PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); - else if (!strict_init_order) - dyn_g.initialized = true; + + if (current_dynamic_init_module_name == nullptr) { + // First call, poison all globals from other modules. + DynInitGlobals().forEach([&](auto &kv) { + if (kv.first != module_name) { + PoisonDynamicGlobals(kv.second); + } else { + UnpoisonDynamicGlobals(kv.second, + /*mark_initialized=*/!strict_init_order); + } + return true; + }); + } else { + // Module changed. + PoisonDynamicGlobals(DynInitGlobals()[current_dynamic_init_module_name]); + UnpoisonDynamicGlobals(DynInitGlobals()[module_name], + /*mark_initialized=*/!strict_init_order); } + current_dynamic_init_module_name = module_name; } +#if SANITIZER_CAN_USE_PREINIT_ARRAY +static bool allow_after_dynamic_init = false; + +static void __attribute__((used)) AfterDynamicInit(void) { + if (flags()->report_globals >= 3) + Printf("AfterDynamicInit\n"); + if (allow_after_dynamic_init) + return; + allow_after_dynamic_init = true; + __asan_after_dynamic_init(); +} + +// Maybe SANITIZER_CAN_USE_PREINIT_ARRAY is to conservative for `.init_array`. +__attribute__((section(".init_array"), constructor(10000), + used)) static void (*__init)(void) = AfterDynamicInit; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY + // This method runs immediately after dynamic initialization in each TU, when // all dynamically initialized globals except for those defined in the current // TU are poisoned. It simply unpoisons all dynamically initialized globals. void __asan_after_dynamic_init() { +#if SANITIZER_CAN_USE_PREINIT_ARRAY + // Ignore all callback until the first one from .init_array, which should + // happed after all C++ global constructors. + if (!allow_after_dynamic_init) + return; +#endif + if (!flags()->check_initialization_order || !CanPoisonMemory()) return; CHECK(AsanInited()); Lock lock(&mu_for_globals); + if (!current_dynamic_init_module_name) + return; + if (flags()->report_globals >= 3) Printf("DynInitUnpoison\n"); - for (const DynInitGlobal &dyn_g : dynamic_init_globals) { - const Global *g = &dyn_g.g; - if (!dyn_g.initialized) { - // Unpoison the whole global. - PoisonShadowForGlobal(g, 0); - // Poison redzones back. - PoisonRedZones(*g); - } - } + + DynInitGlobals().forEach([&](auto &kv) { + UnpoisonDynamicGlobals(kv.second, /*mark_initialized=*/false); + return true; + }); + + current_dynamic_init_module_name = nullptr; } diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 9fb1df7..04bebe3 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1990,6 +1990,11 @@ void ModuleAddressSanitizer::createInitializerPoisonCalls( // Don't instrument CTORs that will run before asan.module_ctor. if (Priority->getLimitedValue() <= GetCtorAndDtorPriority(TargetTriple)) continue; + if (Priority->getLimitedValue() == 65535) { + CS->setOperand(0, + ConstantInt::getSigned(Priority->getType(), + Priority->getLimitedValue() - 1)); + } poisonOneInitializer(*F, ModuleName); } } diff --git a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp index e1bc58f..faca3bc 100644 --- a/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp +++ b/llvm/unittests/Transforms/Utils/ModuleUtilsTest.cpp @@ -24,12 +24,12 @@ static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { return Mod; } -static int getUsedListSize(Module &M, StringRef Name) { - auto *UsedList = M.getGlobalVariable(Name); - if (!UsedList) +static int getListSize(Module &M, StringRef Name) { + auto *List = M.getGlobalVariable(Name); + if (!List) return 0; - auto *UsedListBaseArrayType = cast<ArrayType>(UsedList->getValueType()); - return UsedListBaseArrayType->getNumElements(); + auto *T = cast<ArrayType>(List->getValueType()); + return T->getNumElements(); } TEST(ModuleUtils, AppendToUsedList1) { @@ -41,13 +41,13 @@ TEST(ModuleUtils, AppendToUsedList1) { for (auto &G : M->globals()) { Globals.push_back(&G); } - EXPECT_EQ(0, getUsedListSize(*M, "llvm.compiler.used")); + EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used")); appendToCompilerUsed(*M, Globals); - EXPECT_EQ(1, getUsedListSize(*M, "llvm.compiler.used")); + EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used")); - EXPECT_EQ(0, getUsedListSize(*M, "llvm.used")); + EXPECT_EQ(0, getListSize(*M, "llvm.used")); appendToUsed(*M, Globals); - EXPECT_EQ(1, getUsedListSize(*M, "llvm.used")); + EXPECT_EQ(1, getListSize(*M, "llvm.used")); } TEST(ModuleUtils, AppendToUsedList2) { @@ -59,11 +59,11 @@ TEST(ModuleUtils, AppendToUsedList2) { for (auto &G : M->globals()) { Globals.push_back(&G); } - EXPECT_EQ(0, getUsedListSize(*M, "llvm.compiler.used")); + EXPECT_EQ(0, getListSize(*M, "llvm.compiler.used")); appendToCompilerUsed(*M, Globals); - EXPECT_EQ(1, getUsedListSize(*M, "llvm.compiler.used")); + EXPECT_EQ(1, getListSize(*M, "llvm.compiler.used")); - EXPECT_EQ(0, getUsedListSize(*M, "llvm.used")); + EXPECT_EQ(0, getListSize(*M, "llvm.used")); appendToUsed(*M, Globals); - EXPECT_EQ(1, getUsedListSize(*M, "llvm.used")); + EXPECT_EQ(1, getListSize(*M, "llvm.used")); } |