[asan][windows] Eliminate the static asan runtime on windows by barcharcraz · Pull Request #81677 · llvm/llvm-project (original) (raw)

@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Charlie Barto (barcharcraz)

Changes

This is one of the major changes we (Microsoft) have made in the version of asan we ship with Visual Studio.

Here's the description of these changes from our internal PR

  1. Build one DLL that includes everything debug mode needs (not included here, already contributed upstream).
  1. Redirect statically linked functions to the ASAN DLL for /MT
  1. Support weak symbols for /MD
  1. Build reorganization

In addition:

I have tried to separate things into reasonable commits to make reviewing easier.

Currently this is marked as a draft because there are a few test failures that popped up when I rebased, as well as some failures on mingw.


Patch is 154.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81677.diff

71 Files Affected:

@@ -275,25 +298,11 @@ else() endif() set(ASAN_DYNAMIC_WEAK_INTERCEPTION) - if (WIN32) - add_compiler_rt_object_libraries(AsanWeakInterception - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${arch} - SOURCES - asan_win_weak_interception.cpp - CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DYNAMIC - DEFS ${ASAN_COMMON_DEFINITIONS}) - set(ASAN_DYNAMIC_WEAK_INTERCEPTION - AsanWeakInterception - UbsanWeakInterception - SancovWeakInterception - SanitizerCommonWeakInterception) - endif()

 add_compiler_rt_runtime(clang_rt.asan
   SHARED
   ARCHS ${arch}
   OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}

@@ -321,36 +330,12 @@ else() endif() if (WIN32) - add_compiler_rt_object_libraries(AsanDllThunk - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${arch} - SOURCES asan_globals_win.cpp - asan_win_dll_thunk.cpp - CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DLL_THUNK - DEFS ${ASAN_COMMON_DEFINITIONS})

@@ -358,12 +343,35 @@ else() STATIC ARCHS ${arch} OBJECT_LIBS AsanDynamicRuntimeThunk - UbsanDynamicRuntimeThunk - SancovDynamicRuntimeThunk - SanitizerCommonDynamicRuntimeThunk + UbsanRuntimeThunk + SancovRuntimeThunk + SanitizerRuntimeThunk CFLAGS ASANCFLAGS{ASAN_CFLAGS} ASANCFLAGS{DYNAMIC_RUNTIME_THUNK_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS} PARENT_TARGET asan) + + # mingw does not support static linkage of the CRT + if(NOT MINGW) + set(STATIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_STATIC_RUNTIME_THUNK") + + add_compiler_rt_object_libraries(AsanStaticRuntimeThunk + ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${arch} + SOURCES ${ASAN_STATIC_RUNTIME_THUNK_SOURCES} + CFLAGS ASANDYNAMICCFLAGS{ASAN_DYNAMIC_CFLAGS} ASANDYNAMICCFLAGS{STATIC_RUNTIME_THUNK_CFLAGS} + DEFS ${ASAN_DYNAMIC_DEFINITIONS}) + + add_compiler_rt_runtime(clang_rt.asan_static_runtime_thunk + STATIC + ARCHS ${arch} + OBJECT_LIBS AsanStaticRuntimeThunk + UbsanRuntimeThunk + SancovRuntimeThunk + SanitizerRuntimeThunk + CFLAGS ASANDYNAMICCFLAGS{ASAN_DYNAMIC_CFLAGS} ASANDYNAMICCFLAGS{STATIC_RUNTIME_THUNK_CFLAGS} + DEFS ${ASAN_DYNAMIC_DEFINITIONS} + PARENT_TARGET asan) + endif() endif() endforeach() endif() diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp index 23989843323211..56deb1b0d082b8 100644 --- a/compiler-rt/lib/asan/asan_flags.cpp +++ b/compiler-rt/lib/asan/asan_flags.cpp @@ -11,14 +11,16 @@ // ASan flag parsing logic. //===----------------------------------------------------------------------===// -#include "asan_activation.h" #include "asan_flags.h" + +#include "asan_activation.h" #include "asan_interface_internal.h" #include "asan_stack.h" #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_win_interception.h" #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_platform.h" @@ -47,7 +49,21 @@ static void RegisterAsanFlags(FlagParser *parser, Flags *f) { #undef ASAN_FLAG } -void InitializeFlags() { +static void DisplayHelpMessages(FlagParser *parser) { + // TODO(eugenis): dump all flags at verbosity>=2? + if (Verbosity()) { + ReportUnrecognizedFlags(); + } + + if (common_flags()->help) { + parser->PrintFlagDescriptions(); + } +} + +static void InitializeDefaultFlags() { + Flags *f = flags(); + FlagParser asan_parser; + // Set the default values and prepare for parsing ASan and common flags. SetCommonFlagsDefaults(); { @@ -60,10 +76,8 @@ void InitializeFlags() { cf.exitcode = 1; OverrideCommonFlags(cf); } - Flags *f = flags(); f->SetDefaults(); - FlagParser asan_parser; RegisterAsanFlags(&asan_parser, f); RegisterCommonFlags(&asan_parser); @@ -126,13 +140,12 @@ void InitializeFlags() { InitializeCommonFlags(); - // TODO(eugenis): dump all flags at verbosity>=2? - if (Verbosity()) ReportUnrecognizedFlags(); + // TODO(samsonov): print all of the flags (ASan, LSan, common). + DisplayHelpMessages(&asan_parser); +} - if (common_flags()->help) { - // TODO(samsonov): print all of the flags (ASan, LSan, common). - asan_parser.PrintFlagDescriptions(); - } +static void ProcessFlags() { + Flags f = flags(); // Flag validation: if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { @@ -199,6 +212,67 @@ void InitializeFlags() { } } +void InitializeFlags() { + InitializeDefaultFlags(); + ProcessFlags(); + +#if SANITIZER_WINDOWS + // On Windows, weak symbols are emulated by having the user program + // register which weak functions are defined. + // The ASAN DLL will initialize flags prior to user module initialization, + // so __asan_default_options will not point to the user definition yet. + // We still want to ensure we capture when options are passed via + // __asan_default_options, so we add a callback to be run + // when it is registered with the runtime. + + // There is theoretically time between the initial ProcessFlags and + // registering the weak callback where a weak function could be added and we + // would miss it, but in practice, InitializeFlags will always happen under + // the loader lock (if built as a DLL) and so will any calls to + // __sanitizer_register_weak_function. + AddRegisterWeakFunctionCallback( + reinterpret_cast(__asan_default_options), { + FlagParser asan_parser; + + RegisterAsanFlags(&asan_parser, flags()); + RegisterCommonFlags(&asan_parser); + asan_parser.ParseString(__asan_default_options()); + + DisplayHelpMessages(&asan_parser); + ProcessFlags(); + }); + +# if CAN_SANITIZE_UB + AddRegisterWeakFunctionCallback( + reinterpret_cast(__ubsan_default_options), { + FlagParser ubsan_parser; + + __ubsan::RegisterUbsanFlags(&ubsan_parser, __ubsan::flags()); + RegisterCommonFlags(&ubsan_parser); + ubsan_parser.ParseString(__ubsan_default_options()); + + // To match normal behavior, do not print UBSan help. + ProcessFlags(); + }); +# endif + +# if CAN_SANITIZE_LEAKS + AddRegisterWeakFunctionCallback( + reinterpret_cast(__lsan_default_options), { + FlagParser lsan_parser; + + __lsan::RegisterLsanFlags(&lsan_parser, __lsan::flags()); + RegisterCommonFlags(&lsan_parser); + lsan_parser.ParseString(__lsan_default_options()); + + // To match normal behavior, do not print LSan help. + ProcessFlags(); + }); +# endif + +#endif +} + } // namespace __asan SANITIZER_INTERFACE_WEAK_DEF(const char, __asan_default_options, void) { diff --git a/compiler-rt/lib/asan/asan_globals_win.cpp b/compiler-rt/lib/asan/asan_globals_win.cpp index 19af88ab12b40a..8267f07b9cce49 100644 --- a/compiler-rt/lib/asan/asan_globals_win.cpp +++ b/compiler-rt/lib/asan/asan_globals_win.cpp @@ -28,7 +28,9 @@ static void call_on_globals(void (*hook)(__asan_global *, uptr)) { __asan_global *end = &__asan_globals_end; uptr bytediff = (uptr)end - (uptr)start; if (bytediff % sizeof(__asan_global) != 0) { -#if defined(SANITIZER_DLL_THUNK) || defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) +# if defined(SANITIZER_DLL_THUNK) ||
+ defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) ||
+ defined(SANITIZER_STATIC_RUNTIME_THUNK) __debugbreak(); #else CHECK("corrupt asan global array"); diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 4de2fa356374a6..1ca54d404bcaa3 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -558,6 +558,17 @@ INTERCEPTOR(char *, strcpy, char *to, const char from) { return REAL(strcpy)(to, from); } +// Windows doesn't always define the strdup identifier, +// and when it does it's a macro defined to either _strdup +// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so +// we want to intercept that. push/pop_macro are used to avoid problems +// if this file ends up including <string.h> in the future. +# if SANITIZER_WINDOWS +# pragma push_macro("strdup") +# undef strdup +# define strdup _strdup +# endif + INTERCEPTOR(char, strdup, const char *s) { void ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); @@ -575,7 +586,7 @@ INTERCEPTOR(char, strdup, const char s) { return reinterpret_cast<char*>(new_mem); } -#if ASAN_INTERCEPT___STRDUP +# if ASAN_INTERCEPT___STRDUP INTERCEPTOR(char, __strdup, const char *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); @@ -758,7 +769,7 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); ASAN_INTERCEPT_FUNC(strdup); -#if ASAN_INTERCEPT___STRDUP +# if ASAN_INTERCEPT___STRDUP ASAN_INTERCEPT_FUNC(__strdup); #endif #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX @@ -849,6 +860,10 @@ void InitializeAsanInterceptors() { VReport(1, "AddressSanitizer: libc interceptors initialized\n"); } +# if SANITIZER_WINDOWS +# pragma pop_macro("strdup") +# endif + } // namespace __asan #endif // !SANITIZER_FUCHSIA diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp index 7e1d04c36dd580..3278f072198769 100644 --- a/compiler-rt/lib/asan/asan_malloc_win.cpp +++ b/compiler-rt/lib/asan/asan_malloc_win.cpp @@ -58,97 +58,69 @@ using namespace __asan; // MD: Memory allocation functions are defined in the CRT .dll, // so we have to intercept them before they are called for the first time. -#if ASAN_DYNAMIC -# define ALLOCATION_FUNCTION_ATTRIBUTE -#else -# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE -#endif

extern "C" { -ALLOCATION_FUNCTION_ATTRIBUTE -size_t _msize(void *ptr) { +__declspec(noinline) size_t _msize(void *ptr) { GET_CURRENT_PC_BP_SP; (void)sp; return asan_malloc_usable_size(ptr, pc, bp); }

-ALLOCATION_FUNCTION_ATTRIBUTE -size_t _msize_base(void *ptr) {