From 74694b19e04f3d0408830c879133be12c7b4f5df Mon Sep 17 00:00:00 2001 From: Marcos Pividori Date: Fri, 20 Jan 2017 21:09:36 +0000 Subject: [PATCH] [sanitizer] [asan] Use macros to simplify weak aliases on Windows. This patch adds some useful macros for dealing with pragma directives on Windows. Also, I add appropriate documentation for future users. Differential Revision: https://reviews.llvm.org/D28525 llvm-svn: 292650 --- compiler-rt/lib/asan/asan_globals_win.h | 34 ----------- compiler-rt/lib/asan/asan_win.cc | 30 +++------- compiler-rt/lib/asan/asan_win_dll_thunk.cc | 4 +- .../asan/asan_win_dynamic_runtime_thunk.cc | 4 +- .../lib/sanitizer_common/sanitizer_win.cc | 8 +-- .../lib/sanitizer_common/sanitizer_win_defs.h | 59 +++++++++++++++++++ compiler-rt/lib/ubsan/ubsan_flags.cc | 8 +-- 7 files changed, 77 insertions(+), 70 deletions(-) delete mode 100644 compiler-rt/lib/asan/asan_globals_win.h create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h diff --git a/compiler-rt/lib/asan/asan_globals_win.h b/compiler-rt/lib/asan/asan_globals_win.h deleted file mode 100644 index d4ed9c1f38e1..000000000000 --- a/compiler-rt/lib/asan/asan_globals_win.h +++ /dev/null @@ -1,34 +0,0 @@ -//===-- 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 diff --git a/compiler-rt/lib/asan/asan_win.cc b/compiler-rt/lib/asan/asan_win.cc index 78268d83e539..f04cc32da5ba 100644 --- a/compiler-rt/lib/asan/asan_win.cc +++ b/compiler-rt/lib/asan/asan_win.cc @@ -19,7 +19,6 @@ #include -#include "asan_globals_win.h" #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_report.h" @@ -28,6 +27,7 @@ #include "asan_mapping.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" +#include "sanitizer_common/sanitizer_win_defs.h" using namespace __asan; // NOLINT @@ -44,31 +44,17 @@ uptr __asan_get_shadow_memory_dynamic_address() { return __asan_shadow_memory_dynamic_address; } -// -------------------- A workaround for the absence of weak symbols ----- {{{ -// We don't have a direct equivalent of weak symbols when using MSVC, but we can -// use the /alternatename directive to tell the linker to default a specific -// symbol to a specific value, which works nicely for allocator hooks and -// __asan_default_options(). void __sanitizer_default_malloc_hook(void *ptr, uptr size) { } void __sanitizer_default_free_hook(void *ptr) { } const char* __asan_default_default_options() { return ""; } const char* __asan_default_default_suppressions() { return ""; } void __asan_default_on_error() {} -// 64-bit msvc will not prepend an underscore for symbols. -#ifdef _WIN64 -#pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook") // NOLINT -#pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook") // NOLINT -#pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options") // NOLINT -#pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions") // NOLINT -#pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error") // NOLINT -#else -#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT -#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT -#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT -#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT -#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT -#endif -// }}} + +WIN_WEAK_ALIAS(__sanitizer_malloc_hook, __sanitizer_default_malloc_hook) +WIN_WEAK_ALIAS(__sanitizer_free_hook, __sanitizer_default_free_hook) +WIN_WEAK_ALIAS(__asan_default_options, __asan_default_default_options) +WIN_WEAK_ALIAS(__asan_default_suppressions, __asan_default_default_suppressions) +WIN_WEAK_ALIAS(__asan_on_error, __asan_default_on_error) } // extern "C" // ---------------------- Windows-specific interceptors ---------------- {{{ @@ -368,7 +354,7 @@ __declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *, unsigned long, void *) = asan_thread_init; #endif -ASAN_LINK_GLOBALS_WIN() +WIN_FORCE_LINK(__asan_dso_reg_hook) // }}} } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/compiler-rt/lib/asan/asan_win_dll_thunk.cc index 4764fd0a736c..9cd22a71597e 100644 --- a/compiler-rt/lib/asan/asan_win_dll_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dll_thunk.cc @@ -20,9 +20,9 @@ // 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" +#include "sanitizer_common/sanitizer_win_defs.h" #ifdef _M_IX86 #define WINAPI __stdcall @@ -478,6 +478,6 @@ static void WINAPI asan_thread_init(void *mod, unsigned long reason, __declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *, unsigned long, void *) = asan_thread_init; -ASAN_LINK_GLOBALS_WIN() +WIN_FORCE_LINK(__asan_dso_reg_hook) #endif // ASAN_DLL_THUNK diff --git a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc index 8e42f03c1a0d..f9b4c3f513c4 100644 --- a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -24,7 +24,7 @@ // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK -#include "asan_globals_win.h" +#include "sanitizer_common/sanitizer_win_defs.h" #define WIN32_LEAN_AND_MEAN #include @@ -122,6 +122,6 @@ __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = SetSEHFilter; } -ASAN_LINK_GLOBALS_WIN() +WIN_FORCE_LINK(__asan_dso_reg_hook) #endif // ASAN_DYNAMIC_RUNTIME_THUNK diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc index 9682d2921420..645041d5ab0d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -30,6 +30,7 @@ #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" +#include "sanitizer_win_defs.h" // A macro to tell the compiler that this part of the code cannot be reached, // if the compiler supports this feature. Since we're using this in @@ -946,11 +947,8 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } // of null. extern "C" void __sanitizer_print_memory_profile(int top_percent) {} -#ifdef _WIN64 -#pragma comment(linker, "/alternatename:__sanitizer_print_memory_profile=__sanitizer_default_print_memory_profile") // NOLINT -#else -#pragma comment(linker, "/alternatename:___sanitizer_print_memory_profile=___sanitizer_default_print_memory_profile") // NOLINT -#endif +WIN_WEAK_ALIAS(__sanitizer_print_memory_profile, + __sanitizer_default_print_memory_profile) #endif #endif // _WIN32 diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h new file mode 100644 index 000000000000..a5ec5105268e --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h @@ -0,0 +1,59 @@ +//===-- sanitizer_win_defs.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Common definitions for Windows-specific code. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_WIN_DEFS_H +#define SANITIZER_WIN_DEFS_H + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +#if defined(_WIN64) +#define WIN_SYM_PREFIX +#else +#define WIN_SYM_PREFIX "_" +#endif + +// Intermediate macro to ensure the parameter is expanded before stringified. +#define STRINGIFY(A) #A + +// ----------------- A workaround for the absence of weak symbols -------------- +// We don't have a direct equivalent of weak symbols when using MSVC, but we can +// use the /alternatename directive to tell the linker to default a specific +// symbol to a specific value. +// Take into account that the function will be marked as UNDEF in the symbol +// table of the resulting object file, even if we provided a default value, and +// the linker won't find the default implementation until it links with that +// object file. +// So, suppose we provide a default implementation "fundef" for "fun", and this +// is compiled into the object file "test.obj". +// If we have some code with references to "fun" and we link that code with +// "test.obj", it will work because the linker always link object files. +// But, if "test.obj" is included in a static library, like "test.lib", then the +// liker will only link to "test.obj" if necessary. If we only included the +// definition of "fun", it won't link to "test.obj" (from test.lib) because +// "fun" appears as UNDEF, so it doesn't resolve the symbol "fun", and this will +// result in a link error. +// So, a workaround is to force linkage with the modules that include weak +// definitions, with the following macro: WIN_FORCE_LINK() + +#define WIN_WEAK_ALIAS_(Name, Default) \ + __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY(Name) "="\ + WIN_SYM_PREFIX STRINGIFY(Default))) + +#define WIN_WEAK_ALIAS(Name, Default) \ + WIN_WEAK_ALIAS_(Name, Default) + +#define WIN_FORCE_LINK(Name) \ + __pragma(comment(linker, "/include:" WIN_SYM_PREFIX STRINGIFY(Name))) + +#endif // SANITIZER_WINDOWS +#endif // SANITIZER_WIN_DEFS_H diff --git a/compiler-rt/lib/ubsan/ubsan_flags.cc b/compiler-rt/lib/ubsan/ubsan_flags.cc index e77ba550148a..857694ecd0e7 100644 --- a/compiler-rt/lib/ubsan/ubsan_flags.cc +++ b/compiler-rt/lib/ubsan/ubsan_flags.cc @@ -17,6 +17,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_win_defs.h" namespace __ubsan { @@ -76,11 +77,8 @@ const char *__ubsan_default_options() { return ""; } #if SANITIZER_WINDOWS const char *__ubsan_default_default_options() { return ""; } -# ifdef _WIN64 -# pragma comment(linker, "/alternatename:__ubsan_default_options=__ubsan_default_default_options") -# else -# pragma comment(linker, "/alternatename:___ubsan_default_options=___ubsan_default_default_options") -# endif + +WIN_WEAK_ALIAS(__ubsan_default_options, __ubsan_default_default_options) #endif } // extern "C"