Skip to content
This repository was archived by the owner on May 21, 2019. It is now read-only.

Commit 46efcb0

Browse files
author
Alexey Samsonov
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@182637 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 2811a0c commit 46efcb0

File tree

6 files changed

+89
-0
lines changed

6 files changed

+89
-0
lines changed

lib/asan/asan_globals.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,21 @@ static void UnregisterGlobal(const Global *g) {
123123
// implementation. It might not be worth doing anyway.
124124
}
125125

126+
void StopInitOrderChecking() {
127+
BlockingMutexLock lock(&mu_for_globals);
128+
if (!flags()->check_initialization_order || !dynamic_init_globals)
129+
return;
130+
flags()->check_initialization_order = false;
131+
for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
132+
DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
133+
const Global *g = &dyn_g.g;
134+
// Unpoison the whole global.
135+
PoisonShadowForGlobal(g, 0);
136+
// Poison redzones back.
137+
PoisonRedZones(*g);
138+
}
139+
}
140+
126141
} // namespace __asan
127142

128143
// ---------------------- Interface ---------------- {{{1

lib/asan/asan_intercepted_functions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ using __sanitizer::uptr;
7777
# define ASAN_INTERCEPT___CXA_THROW 0
7878
#endif
7979

80+
#if !SANITIZER_WINDOWS
81+
# define ASAN_INTERCEPT___CXA_ATEXIT 1
82+
#else
83+
# define ASAN_INTERCEPT___CXA_ATEXIT 0
84+
#endif
85+
8086
# if SANITIZER_WINDOWS
8187
extern "C" {
8288
// Windows threads.

lib/asan/asan_interceptors.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,21 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
636636
}
637637
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
638638

639+
static void AtCxaAtexit(void *unused) {
640+
(void)unused;
641+
StopInitOrderChecking();
642+
}
643+
644+
#if ASAN_INTERCEPT___CXA_ATEXIT
645+
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
646+
void *dso_handle) {
647+
ENSURE_ASAN_INITED();
648+
int res = REAL(__cxa_atexit)(func, arg, dso_handle);
649+
REAL(__cxa_atexit)(AtCxaAtexit, 0, 0);
650+
return res;
651+
}
652+
#endif // ASAN_INTERCEPT___CXA_ATEXIT
653+
639654
#define ASAN_INTERCEPT_FUNC(name) do { \
640655
if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
641656
Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
@@ -746,6 +761,11 @@ void InitializeAsanInterceptors() {
746761
ASAN_INTERCEPT_FUNC(pthread_create);
747762
#endif
748763

764+
// Intercept atexit function.
765+
#if ASAN_INTERCEPT___CXA_ATEXIT
766+
ASAN_INTERCEPT_FUNC(__cxa_atexit);
767+
#endif
768+
749769
// Some Windows-specific interceptors.
750770
#if SANITIZER_WINDOWS
751771
InitializeWindowsInterceptors();

lib/asan/asan_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ void UnsetAlternateSignalStack();
9292
void InstallSignalHandlers();
9393
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
9494
void AsanPlatformThreadInit();
95+
void StopInitOrderChecking();
9596

9697
// Wrapper for TLS/TSD.
9798
void AsanTSDInit(void (*destructor)(void *tsd));
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <stdio.h>
2+
3+
class C {
4+
public:
5+
C() { value = 42; }
6+
~C() { }
7+
int value;
8+
};
9+
10+
C c;
11+
12+
void AccessC() {
13+
printf("C value: %d\n", c.value);
14+
}
15+
16+
int main() { return 0; }
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Test for the following situation:
2+
// (1) global A is constructed.
3+
// (2) exit() is called during construction of global B.
4+
// (3) destructor of A reads uninitialized global C from another module.
5+
// We do *not* want to report init-order bug in this case.
6+
7+
// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t
8+
// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 | FileCheck %s
9+
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
13+
void AccessC();
14+
15+
class A {
16+
public:
17+
A() { }
18+
~A() { AccessC(); printf("PASSED\n"); }
19+
// CHECK-NOT: AddressSanitizer
20+
// CHECK: PASSED
21+
};
22+
23+
A a;
24+
25+
class B {
26+
public:
27+
B() { exit(1); }
28+
~B() { }
29+
};
30+
31+
B b;

0 commit comments

Comments
 (0)