forked from OSchip/llvm-project
Disable init-order checking before destructors are run.
We don't want to report initialization-order bugs when a destructor of a global variable accesses dynamically initialized global from another (not necessarily initialized) module. We do this by intercepting __cxa_atexit and registrering our own callback that unpoisons shadow for all dynamically initialized global variables. llvm-svn: 182637
This commit is contained in:
parent
534d3a4670
commit
646ec67e25
|
@ -123,6 +123,21 @@ static void UnregisterGlobal(const Global *g) {
|
|||
// implementation. It might not be worth doing anyway.
|
||||
}
|
||||
|
||||
void StopInitOrderChecking() {
|
||||
BlockingMutexLock lock(&mu_for_globals);
|
||||
if (!flags()->check_initialization_order || !dynamic_init_globals)
|
||||
return;
|
||||
flags()->check_initialization_order = false;
|
||||
for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
|
||||
DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
|
||||
const Global *g = &dyn_g.g;
|
||||
// Unpoison the whole global.
|
||||
PoisonShadowForGlobal(g, 0);
|
||||
// Poison redzones back.
|
||||
PoisonRedZones(*g);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
|
|
|
@ -77,6 +77,12 @@ using __sanitizer::uptr;
|
|||
# define ASAN_INTERCEPT___CXA_THROW 0
|
||||
#endif
|
||||
|
||||
#if !SANITIZER_WINDOWS
|
||||
# define ASAN_INTERCEPT___CXA_ATEXIT 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___CXA_ATEXIT 0
|
||||
#endif
|
||||
|
||||
# if SANITIZER_WINDOWS
|
||||
extern "C" {
|
||||
// Windows threads.
|
||||
|
|
|
@ -636,6 +636,21 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
|
|||
}
|
||||
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
|
||||
static void AtCxaAtexit(void *unused) {
|
||||
(void)unused;
|
||||
StopInitOrderChecking();
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT___CXA_ATEXIT
|
||||
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
|
||||
void *dso_handle) {
|
||||
ENSURE_ASAN_INITED();
|
||||
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
|
||||
REAL(__cxa_atexit)(AtCxaAtexit, 0, 0);
|
||||
return res;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT___CXA_ATEXIT
|
||||
|
||||
#define ASAN_INTERCEPT_FUNC(name) do { \
|
||||
if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
|
||||
Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
|
||||
|
@ -746,6 +761,11 @@ void InitializeAsanInterceptors() {
|
|||
ASAN_INTERCEPT_FUNC(pthread_create);
|
||||
#endif
|
||||
|
||||
// Intercept atexit function.
|
||||
#if ASAN_INTERCEPT___CXA_ATEXIT
|
||||
ASAN_INTERCEPT_FUNC(__cxa_atexit);
|
||||
#endif
|
||||
|
||||
// Some Windows-specific interceptors.
|
||||
#if SANITIZER_WINDOWS
|
||||
InitializeWindowsInterceptors();
|
||||
|
|
|
@ -92,6 +92,7 @@ void UnsetAlternateSignalStack();
|
|||
void InstallSignalHandlers();
|
||||
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
|
||||
void AsanPlatformThreadInit();
|
||||
void StopInitOrderChecking();
|
||||
|
||||
// Wrapper for TLS/TSD.
|
||||
void AsanTSDInit(void (*destructor)(void *tsd));
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdio.h>
|
||||
|
||||
class C {
|
||||
public:
|
||||
C() { value = 42; }
|
||||
~C() { }
|
||||
int value;
|
||||
};
|
||||
|
||||
C c;
|
||||
|
||||
void AccessC() {
|
||||
printf("C value: %d\n", c.value);
|
||||
}
|
||||
|
||||
int main() { return 0; }
|
|
@ -0,0 +1,31 @@
|
|||
// Test for the following situation:
|
||||
// (1) global A is constructed.
|
||||
// (2) exit() is called during construction of global B.
|
||||
// (3) destructor of A reads uninitialized global C from another module.
|
||||
// We do *not* want to report init-order bug in this case.
|
||||
|
||||
// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t
|
||||
// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 | FileCheck %s
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void AccessC();
|
||||
|
||||
class A {
|
||||
public:
|
||||
A() { }
|
||||
~A() { AccessC(); printf("PASSED\n"); }
|
||||
// CHECK-NOT: AddressSanitizer
|
||||
// CHECK: PASSED
|
||||
};
|
||||
|
||||
A a;
|
||||
|
||||
class B {
|
||||
public:
|
||||
B() { exit(1); }
|
||||
~B() { }
|
||||
};
|
||||
|
||||
B b;
|
Loading…
Reference in New Issue