Index: compiler-rt/trunk/lib/asan/CMakeLists.txt =================================================================== --- compiler-rt/trunk/lib/asan/CMakeLists.txt +++ compiler-rt/trunk/lib/asan/CMakeLists.txt @@ -9,6 +9,7 @@ asan_fake_stack.cc asan_flags.cc asan_globals.cc + asan_globals_win.cc asan_interceptors.cc asan_linux.cc asan_mac.cc @@ -63,6 +64,7 @@ append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS) append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS) +append_list_if(MSVC /INCREMENTAL:NO ASAN_DYNAMIC_LINK_FLAGS) append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) @@ -205,6 +207,7 @@ STATIC ARCHS ${arch} SOURCES asan_win_dll_thunk.cc + asan_globals_win.cc $ CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK DEFS ${ASAN_COMMON_DEFINITIONS} @@ -221,6 +224,7 @@ STATIC ARCHS ${arch} SOURCES asan_win_dynamic_runtime_thunk.cc + asan_globals_win.cc CFLAGS ${ASAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS} PARENT_TARGET asan) Index: compiler-rt/trunk/lib/asan/asan_globals.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_globals.cc +++ compiler-rt/trunk/lib/asan/asan_globals.cc @@ -192,6 +192,7 @@ // This function may be called more than once for every global // so we store the globals in a map. static void RegisterGlobal(const Global *g) { + CHECK(g->beg); CHECK(asan_inited); if (flags()->report_globals >= 2) ReportGlobal(*g, "Added"); Index: compiler-rt/trunk/lib/asan/asan_globals_win.h =================================================================== --- compiler-rt/trunk/lib/asan/asan_globals_win.h +++ compiler-rt/trunk/lib/asan/asan_globals_win.h @@ -0,0 +1,34 @@ +//===-- asan_globals_win.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Interface to the Windows-specific global management code. Separated into a +// standalone header to allow inclusion from asan_win_dynamic_runtime_thunk, +// which defines symbols that clash with other sanitizer headers. +// +//===----------------------------------------------------------------------===// + +#ifndef ASAN_GLOBALS_WIN_H +#define ASAN_GLOBALS_WIN_H + +#if !defined(_MSC_VER) +#error "this file is Windows-only, and uses MSVC pragmas" +#endif + +#if defined(_WIN64) +#define SANITIZER_SYM_PREFIX +#else +#define SANITIZER_SYM_PREFIX "_" +#endif + +// Use this macro to force linking asan_globals_win.cc into the DSO. +#define ASAN_LINK_GLOBALS_WIN() \ + __pragma( \ + comment(linker, "/include:" SANITIZER_SYM_PREFIX "__asan_dso_reg_hook")) + +#endif // ASAN_GLOBALS_WIN_H Index: compiler-rt/trunk/lib/asan/asan_globals_win.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_globals_win.cc +++ compiler-rt/trunk/lib/asan/asan_globals_win.cc @@ -0,0 +1,54 @@ +//===-- asan_globals_win.cc -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Global registration code that is linked into every Windows DLL and EXE. +// +//===----------------------------------------------------------------------===// + +#include "asan_interface_internal.h" +#if SANITIZER_WINDOWS + +namespace __asan { + +#pragma section(".ASAN$GA", read, write) // NOLINT +#pragma section(".ASAN$GZ", read, write) // NOLINT +extern "C" __declspec(allocate(".ASAN$GA")) +uptr __asan_globals_start = 0; +extern "C" __declspec(allocate(".ASAN$GZ")) +uptr __asan_globals_end = 0; +#pragma comment(linker, "/merge:.ASAN=.data") + +static void call_on_globals(void (*hook)(__asan_global *, uptr)) { + __asan_global *start = (__asan_global *)(&__asan_globals_start + 1); + __asan_global *end = (__asan_global *)&__asan_globals_end; + // We know end >= start because the linker sorts the portion after the dollar + // sign alphabetically. + uptr n = end - start; + hook(start, n); +} + +static void register_dso_globals() { + call_on_globals(&__asan_register_globals); +} + +static void unregister_dso_globals() { + call_on_globals(&__asan_unregister_globals); +} + +// Register globals +#pragma section(".CRT$XCU", long, read) // NOLINT +#pragma section(".CRT$XTX", long, read) // NOLINT +extern "C" __declspec(allocate(".CRT$XCU")) +void (*const __asan_dso_reg_hook)() = ®ister_dso_globals; +extern "C" __declspec(allocate(".CRT$XTX")) +void (*const __asan_dso_unreg_hook)() = &unregister_dso_globals; + +} // namespace __asan + +#endif // SANITIZER_WINDOWS Index: compiler-rt/trunk/lib/asan/asan_win.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_win.cc +++ compiler-rt/trunk/lib/asan/asan_win.cc @@ -19,6 +19,7 @@ #include +#include "asan_globals_win.h" #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_report.h" @@ -367,8 +368,9 @@ unsigned long, void *) = asan_thread_init; #endif +ASAN_LINK_GLOBALS_WIN() // }}} } // namespace __asan -#endif // _WIN32 +#endif // SANITIZER_WINDOWS Index: compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc +++ compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc @@ -20,6 +20,7 @@ // simplifies the build procedure. #ifdef ASAN_DLL_THUNK #include "asan_init_version.h" +#include "asan_globals_win.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" @@ -472,4 +473,6 @@ __declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *, unsigned long, void *) = asan_thread_init; +ASAN_LINK_GLOBALS_WIN() + #endif // ASAN_DLL_THUNK Index: compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -24,6 +24,7 @@ // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK +#include "asan_globals_win.h" #define WIN32_LEAN_AND_MEAN #include @@ -121,4 +122,6 @@ SetSEHFilter; } +ASAN_LINK_GLOBALS_WIN() + #endif // ASAN_DYNAMIC_RUNTIME_THUNK Index: compiler-rt/trunk/lib/asan/tests/CMakeLists.txt =================================================================== --- compiler-rt/trunk/lib/asan/tests/CMakeLists.txt +++ compiler-rt/trunk/lib/asan/tests/CMakeLists.txt @@ -47,6 +47,8 @@ endif() if(MSVC) list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gcodeview) + # Incremental linking appears to break our global registration mechanism. + list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -Wl,-incremental:no) endif() list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -g) Index: compiler-rt/trunk/test/asan/TestCases/Windows/dll_global_dead_strip.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/Windows/dll_global_dead_strip.c +++ compiler-rt/trunk/test/asan/TestCases/Windows/dll_global_dead_strip.c @@ -0,0 +1,31 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=NOSTRIP +// RUN: %clang_cl_asan -LD -O2 %s -Fe%t.dll -link -opt:ref +// RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=STRIP + +// FIXME: Remove the XFAIL once the LLVM instrumentation change lands. +// XFAIL: * + +#include + +int dead_global = 42; +int live_global = 0; + +__declspec(dllexport) +int test_function() { + puts("main"); + return live_global; +} + +// Check that our global registration scheme works with MSVC's linker dead +// stripping (/OPT:REF). + +// NOSTRIP: Added Global{{.*}}name=dead_global +// NOSTRIP: Added Global{{.*}}name=live_global +// NOSTRIP: main + +// STRIP-NOT: Added Global{{.*}}name=dead_global +// STRIP: Added Global{{.*}}name=live_global +// STRIP: main Index: compiler-rt/trunk/test/asan/TestCases/Windows/global_dead_strip.c =================================================================== --- compiler-rt/trunk/test/asan/TestCases/Windows/global_dead_strip.c +++ compiler-rt/trunk/test/asan/TestCases/Windows/global_dead_strip.c @@ -0,0 +1,26 @@ +// RUN: %clang_cl_asan /O0 %s /Fe%t.exe +// RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=NOSTRIP +// RUN: %clang_cl_asan /O2 %s /Fe%t.exe -link -opt:ref +// RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=STRIP + +// FIXME: Remove the XFAIL once the LLVM instrumentation change lands. +// XFAIL: * + +#include +int dead_global = 42; +int live_global = 0; +int main() { + puts("main"); + return live_global; +} + +// Check that our global registration scheme works with MSVC's linker dead +// stripping (/OPT:REF). + +// NOSTRIP: Added Global{{.*}}name=dead_global +// NOSTRIP: Added Global{{.*}}name=live_global +// NOSTRIP: main + +// STRIP-NOT: Added Global{{.*}}name=dead_global +// STRIP: Added Global{{.*}}name=live_global +// STRIP: main