From f535d33fee75d2f3fd75e05b9414549e7db594e3 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Tue, 24 Feb 2015 00:37:27 +0000 Subject: [PATCH] [ASan] Disable strict init-order checking if dlopen() is called. Revise the fix to https://code.google.com/p/address-sanitizer/issues/detail?id=178: always disable strict init-order checking the first time dlopen() is called: at this point shared library is allowed to access globals defined in the main executable, as they are guaranteed to be initialized. Revise the test cases: * simplify init-order-dlopen.cc test case: make it Linux-specific (there's no strict init-order checking on other platforms anyway), and single-threaded. * reinforce init-order-pthread-create.cc test case: make sure that init-order checker would produce a false positive unless we turn it off at the moment we call pthread_create(). llvm-svn: 230288 --- compiler-rt/lib/asan/asan_interceptors.cc | 6 ++ .../sanitizer_common_interceptors.inc | 6 ++ .../Helpers/init-order-pthread-create-extra.cc | 4 +- .../test/asan/TestCases/Linux/init-order-dlopen.cc | 43 +++++++++++++ .../test/asan/TestCases/Posix/init-order-dlopen.cc | 72 ---------------------- .../asan/TestCases/init-order-pthread-create.cc | 37 +++++++---- 6 files changed, 81 insertions(+), 87 deletions(-) create mode 100644 compiler-rt/test/asan/TestCases/Linux/init-order-dlopen.cc delete mode 100644 compiler-rt/test/asan/TestCases/Posix/init-order-dlopen.cc diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 3dc7ec6..df57696 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -171,6 +171,12 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) do { \ } while (false) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +// Strict init-order checking is dlopen-hostile: +// https://code.google.com/p/address-sanitizer/issues/detail?id=178 +#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \ + if (flags()->strict_init_order) { \ + StopInitOrderChecking(); \ + } #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ CoverageUpdateMapping() diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 87c33e1..2f1930a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -22,6 +22,7 @@ // COMMON_INTERCEPTOR_FD_RELEASE // COMMON_INTERCEPTOR_FD_ACCESS // COMMON_INTERCEPTOR_SET_THREAD_NAME +// COMMON_INTERCEPTOR_ON_DLOPEN // COMMON_INTERCEPTOR_ON_EXIT // COMMON_INTERCEPTOR_MUTEX_LOCK // COMMON_INTERCEPTOR_MUTEX_UNLOCK @@ -101,6 +102,10 @@ #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0) #endif +#ifndef COMMON_INTERCEPTOR_ON_DLOPEN +#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) {} +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -4688,6 +4693,7 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { INTERCEPTOR(void*, dlopen, const char *filename, int flag) { void *ctx; COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag); + COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag); void *res = REAL(dlopen)(filename, flag); COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res); return res; diff --git a/compiler-rt/test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc b/compiler-rt/test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc index d4606f0..54f26f1 100644 --- a/compiler-rt/test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc +++ b/compiler-rt/test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc @@ -1,2 +1,2 @@ -void *bar(void *input); -void *glob2 = bar((void*)0x2345); +void *bar(void *input, bool sleep_before_init); +void *glob2 = bar((void*)0x2345, true); diff --git a/compiler-rt/test/asan/TestCases/Linux/init-order-dlopen.cc b/compiler-rt/test/asan/TestCases/Linux/init-order-dlopen.cc new file mode 100644 index 0000000..17ba9d0 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Linux/init-order-dlopen.cc @@ -0,0 +1,43 @@ +// Regression test for +// https://code.google.com/p/address-sanitizer/issues/detail?id=178 + +// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O0 %s %libdl -Wl,--export-dynamic -o %t +// RUN: env ASAN_OPTIONS=strict_init_order=true %run %t 2>&1 + +#if defined(SHARED_LIB) +#include + +struct Bar { + Bar(int val) : val(val) { printf("Bar::Bar(%d)\n", val); } + int val; +}; + +int get_foo_val(); +Bar global_bar(get_foo_val()); +#else // SHARED LIB +#include +#include +#include +struct Foo { + Foo() : val(42) { printf("Foo::Foo()\n"); } + int val; +}; + +Foo global_foo; + +int get_foo_val() { + return global_foo.val; +} + +int main(int argc, char *argv[]) { + std::string path = std::string(argv[0]) + "-so.so"; + void *handle = dlopen(path.c_str(), RTLD_NOW); + if (!handle) { + printf("error in dlopen(): %s\n", dlerror()); + return 1; + } + printf("%d\n", get_foo_val()); + return 0; +} +#endif // SHARED_LIB diff --git a/compiler-rt/test/asan/TestCases/Posix/init-order-dlopen.cc b/compiler-rt/test/asan/TestCases/Posix/init-order-dlopen.cc deleted file mode 100644 index 3c6f093..0000000 --- a/compiler-rt/test/asan/TestCases/Posix/init-order-dlopen.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Regression test for -// https://code.google.com/p/address-sanitizer/issues/detail?id=178 - -// Assume we're on Darwin and try to pass -U to the linker. If this flag is -// unsupported, don't use it. -// RUN: %clangxx_asan -O0 -DSHARED_LIB %s \ -// RUN: -fPIC -shared -o %t-so.so -Wl,-U,_inc_global || \ -// RUN: %clangxx_asan -O0 -DSHARED_LIB %s \ -// RUN: -fPIC -shared -o %t-so.so -// If the linker doesn't support --export-dynamic (which is ELF-specific), -// try to link without that option. -// FIXME: find a better solution. -// RUN: %clangxx_asan -O0 %s -pthread %libdl -o %t -Wl,--export-dynamic || \ -// RUN: %clangxx_asan -O0 %s -pthread %libdl -o %t -// RUN: ASAN_OPTIONS=strict_init_order=true %run %t 2>&1 | FileCheck %s -#if !defined(SHARED_LIB) -#include -#include -#include -#include - -#include - -using std::string; - -int foo() { - return 42; -} -int global = foo(); - -__attribute__((visibility("default"))) -extern "C" -void inc_global() { - global++; -} - -void *global_poller(void *arg) { - while (true) { - if (global != 42) - break; - usleep(100); - } - return 0; -} - -int main(int argc, char *argv[]) { - pthread_t p; - pthread_create(&p, 0, global_poller, 0); - string path = string(argv[0]) + "-so.so"; - if (0 == dlopen(path.c_str(), RTLD_NOW)) { - fprintf(stderr, "dlerror: %s\n", dlerror()); - return 1; - } - pthread_join(p, 0); - printf("PASSED\n"); - // CHECK: PASSED - return 0; -} -#else // SHARED_LIB -#include -#include - -extern "C" void inc_global(); - -int slow_init() { - sleep(1); - inc_global(); - return 42; -} - -int slowly_init_glob = slow_init(); -#endif // SHARED_LIB diff --git a/compiler-rt/test/asan/TestCases/init-order-pthread-create.cc b/compiler-rt/test/asan/TestCases/init-order-pthread-create.cc index eeff308..b8bc93e 100644 --- a/compiler-rt/test/asan/TestCases/init-order-pthread-create.cc +++ b/compiler-rt/test/asan/TestCases/init-order-pthread-create.cc @@ -6,25 +6,36 @@ #include #include +#include -void *run(void *arg) { - return arg; +void *bar(void *input, bool sleep_before_init) { + if (sleep_before_init) + usleep(500000); + return input; } -void *foo(void *input) { - pthread_t t; - pthread_create(&t, 0, run, input); - void *res; - pthread_join(t, &res); - return res; -} +void *glob = bar((void*)0x1234, false); +extern void *glob2; -void *bar(void *input) { - return input; +void *poll(void *arg) { + void **glob = (void**)arg; + while (true) { + usleep(100000); + printf("glob is now: %p\n", *glob); + } } -void *glob = foo((void*)0x1234); -extern void *glob2; +struct GlobalPollerStarter { + GlobalPollerStarter() { + pthread_t p; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&p, 0, poll, &glob); + pthread_attr_destroy(&attr); + printf("glob poller is started"); + } +} global_poller; int main() { printf("%p %p\n", glob, glob2); -- 2.7.4