Index: lib/asan/CMakeLists.txt =================================================================== --- lib/asan/CMakeLists.txt +++ 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 @@ -205,6 +206,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 +223,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: lib/asan/asan_globals.cc =================================================================== --- lib/asan/asan_globals.cc +++ 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: lib/asan/asan_globals_win.h =================================================================== --- /dev/null +++ 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: lib/asan/asan_globals_win.cc =================================================================== --- /dev/null +++ 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: lib/asan/asan_win.cc =================================================================== --- lib/asan/asan_win.cc +++ 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: lib/asan/asan_win_dll_thunk.cc =================================================================== --- lib/asan/asan_win_dll_thunk.cc +++ 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: lib/asan/asan_win_dynamic_runtime_thunk.cc =================================================================== --- lib/asan/asan_win_dynamic_runtime_thunk.cc +++ 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: lib/asan/tests/CMakeLists.txt =================================================================== --- lib/asan/tests/CMakeLists.txt +++ 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: test/asan/TestCases/Windows/global-dead-strip.c =================================================================== --- /dev/null +++ test/asan/TestCases/Windows/global-dead-strip.c @@ -0,0 +1,17 @@ +// 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 +// RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=STRIP + +#include +int dead_global = 42; +int main() { puts("main"); } + +// Check that our global registration scheme works with MSVC's linker dead +// stripping (/OPT:REF). + +// NOSTRIP: Added Global{{.*}}name=dead_global +// NOSTRIP: main + +// STRIP-NOT: Added Global{{.*}}name=dead_global +// STRIP: main