diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 273f215ca94a8..7b7fd2d9d4742 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -909,10 +909,16 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, DiagnoseErrors); } - SharedRuntime = - Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan, - TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || - TC.getTriple().isOSDarwin()); + SharedRuntime = Args.hasFlag( + options::OPT_shared_libsan, options::OPT_static_libsan, + TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() || + TC.getTriple().isOSDarwin() || TC.getTriple().isOSWindows()); + if (!SharedRuntime && TC.getTriple().isOSWindows()) { + Arg *A = + Args.getLastArg(options::OPT_shared_libsan, options::OPT_static_libsan); + D.Diag(clang::diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << TC.getTriple().str(); + } ImplicitCfiRuntime = TC.getTriple().isAndroid(); diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index b7021d4b996dd..bf54f04363851 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -201,10 +201,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (TC.getSanitizerArgs(Args).needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); - if (TC.getSanitizerArgs(Args).needsSharedRt() || - Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { - for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) - CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic")); + auto defines = Args.getAllArgValues(options::OPT_D); + if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd) || + find(begin(defines), end(defines), "_DLL") != end(defines)) { // Make sure the dynamic runtime thunk is not optimized out at link time // to ensure proper SEH handling. CmdArgs.push_back(Args.MakeArgString( @@ -213,19 +213,15 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, : "-include:__asan_seh_interceptor")); // Make sure the linker consider all object files from the dynamic runtime // thunk. - CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + + CmdArgs.push_back(Args.MakeArgString( + std::string("-wholearchive:") + TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk"))); - } else if (DLL) { - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); } else { - for (const auto &Lib : {"asan", "asan_cxx"}) { - CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); - // Make sure the linker consider all object files from the static lib. - // This is necessary because instrumented dlls need access to all the - // interface exported by the static lib in the main executable. - CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + - TC.getCompilerRT(Args, Lib))); - } + // Make sure the linker consider all object files from the static runtime + // thunk. + CmdArgs.push_back(Args.MakeArgString( + std::string("-wholearchive:") + + TC.getCompilerRT(Args, "asan_static_runtime_thunk"))); } } diff --git a/clang/test/Driver/cl-link.c b/clang/test/Driver/cl-link.c index ffd0b5ac4bade..f526044276045 100644 --- a/clang/test/Driver/cl-link.c +++ b/clang/test/Driver/cl-link.c @@ -13,10 +13,8 @@ // ASAN: link.exe // ASAN: "-debug" // ASAN: "-incremental:no" -// ASAN: "{{[^"]*}}clang_rt.asan.lib" -// ASAN: "-wholearchive:{{.*}}clang_rt.asan.lib" -// ASAN: "{{[^"]*}}clang_rt.asan_cxx.lib" -// ASAN: "-wholearchive:{{.*}}clang_rt.asan_cxx.lib" +// ASAN: "{{[^"]*}}clang_rt.asan_dynamic.lib" +// ASAN: "-wholearchive:{{.*}}clang_rt.asan_static_runtime_thunk.lib" // ASAN: "{{.*}}cl-link{{.*}}.obj" // RUN: %clang_cl -m32 -arch:IA32 --target=i386-pc-win32 /MD /Tc%s -fuse-ld=link -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-MD %s @@ -24,7 +22,6 @@ // ASAN-MD: "-debug" // ASAN-MD: "-incremental:no" // ASAN-MD: "{{.*}}clang_rt.asan_dynamic.lib" -// ASAN-MD: "{{[^"]*}}clang_rt.asan_dynamic_runtime_thunk.lib" // ASAN-MD: "-include:___asan_seh_interceptor" // ASAN-MD: "-wholearchive:{{.*}}clang_rt.asan_dynamic_runtime_thunk.lib" // ASAN-MD: "{{.*}}cl-link{{.*}}.obj" @@ -40,7 +37,8 @@ // ASAN-DLL: "-dll" // ASAN-DLL: "-debug" // ASAN-DLL: "-incremental:no" -// ASAN-DLL: "{{.*}}clang_rt.asan_dll_thunk.lib" +// ASAN-DLL: "{{.*}}clang_rt.asan_dynamic.lib" +// ASAN-DLL: "-wholearchive:{{.*}}clang_rt.asan_static_runtime_thunk.lib" // ASAN-DLL: "{{.*}}cl-link{{.*}}.obj" // RUN: %clang_cl /Zi /Tc%s -fuse-ld=link -### 2>&1 | FileCheck --check-prefix=DEBUG %s diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index 6ce451e3cac2e..158fa270c3f15 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -378,8 +378,12 @@ if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "s390x") endif() if(MSVC) - # FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214. - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) + + # asan on windows only supports the release dll version of the runtimes, in the interest of + # only having one asan dll to support/test. Having asan statically linked + # with the runtime might be possible, but it multiplies the number of scenerios to test. + # the program USING sanitizers can use whatever version of the runtime it wants to. + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) # Remove any /M[DT][d] flags, and strip any definitions of _DEBUG. # Since we're using CMAKE_MSVC_RUNTIME_LIBRARY (CMP0091 set to NEW), diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt index 463ea233b37aa..f992419c6d982 100644 --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -32,6 +32,20 @@ set(ASAN_SOURCES asan_win.cpp ) +if(WIN32) + set(ASAN_DYNAMIC_RUNTIME_THUNK_SOURCES + asan_globals_win.cpp + asan_win_common_runtime_thunk.cpp + asan_win_dynamic_runtime_thunk.cpp + ) + set(ASAN_STATIC_RUNTIME_THUNK_SOURCES + asan_globals_win.cpp + asan_malloc_win_thunk.cpp + asan_win_common_runtime_thunk.cpp + asan_win_static_runtime_thunk.cpp + ) +endif() + if (NOT WIN32 AND NOT APPLE) list(APPEND ASAN_SOURCES asan_interceptors_vfork.S @@ -136,7 +150,7 @@ append_list_if(MINGW "${MINGW_LIBRARIES}" ASAN_DYNAMIC_LIBS) add_compiler_rt_object_libraries(RTAsan_dynamic OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${ASAN_SUPPORTED_ARCH} - SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES} + SOURCES ${ASAN_SOURCES} ADDITIONAL_HEADERS ${ASAN_HEADERS} CFLAGS ${ASAN_DYNAMIC_CFLAGS} DEFS ${ASAN_DYNAMIC_DEFINITIONS}) @@ -221,46 +235,52 @@ else() RTSanitizerCommonSymbolizerInternal RTLSanCommon RTUbsan) + if (NOT WIN32) + add_compiler_rt_runtime(clang_rt.asan + STATIC + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_preinit + RTAsan + ${ASAN_COMMON_RUNTIME_OBJECT_LIBS} + CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) - add_compiler_rt_runtime(clang_rt.asan - STATIC - ARCHS ${ASAN_SUPPORTED_ARCH} - OBJECT_LIBS RTAsan_preinit - RTAsan - ${ASAN_COMMON_RUNTIME_OBJECT_LIBS} - CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS} - PARENT_TARGET asan) - - add_compiler_rt_runtime(clang_rt.asan_cxx - STATIC - ARCHS ${ASAN_SUPPORTED_ARCH} - OBJECT_LIBS RTAsan_cxx - RTUbsan_cxx - CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS} - PARENT_TARGET asan) + add_compiler_rt_runtime(clang_rt.asan_cxx + STATIC + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_cxx + RTUbsan_cxx + CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) - add_compiler_rt_runtime(clang_rt.asan_static - STATIC - ARCHS ${ASAN_SUPPORTED_ARCH} - OBJECT_LIBS RTAsan_static - CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS} - PARENT_TARGET asan) + add_compiler_rt_runtime(clang_rt.asan_static + STATIC + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_static + CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) - add_compiler_rt_runtime(clang_rt.asan-preinit - STATIC - ARCHS ${ASAN_SUPPORTED_ARCH} - OBJECT_LIBS RTAsan_preinit - CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS} - PARENT_TARGET asan) + add_compiler_rt_runtime(clang_rt.asan-preinit + STATIC + ARCHS ${ASAN_SUPPORTED_ARCH} + OBJECT_LIBS RTAsan_preinit + CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS} + PARENT_TARGET asan) + endif() foreach(arch ${ASAN_SUPPORTED_ARCH}) if (COMPILER_RT_HAS_VERSION_SCRIPT) + if(WIN32) + set(SANITIZER_RT_VERSION_LIST_LIBS clang_rt.asan-${arch}) + else() + set(SANITIZER_RT_VERSION_LIST_LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch}) + endif() add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch} - LIBS clang_rt.asan-${arch} clang_rt.asan_cxx-${arch} + LIBS ${SANITIZER_RT_VERSION_LIST_LIBS} EXTRA asan.syms.extra) set(VERSION_SCRIPT_FLAG -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers) @@ -278,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} + RTAsan_cxx RTAsan_dynamic # The only purpose of RTAsan_dynamic_version_script_dummy is to # carry a dependency of the shared runtime on the version script. @@ -324,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}) - - add_compiler_rt_runtime(clang_rt.asan_dll_thunk - STATIC - ARCHS ${arch} - OBJECT_LIBS AsanDllThunk - UbsanDllThunk - SancovDllThunk - SanitizerCommonDllThunk - SOURCES $ - PARENT_TARGET asan) - set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_DYNAMIC_RUNTIME_THUNK") - if(MSVC) - list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-Zl") - elseif(CMAKE_C_COMPILER_ID MATCHES Clang) - list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-nodefaultlibs") - endif() add_compiler_rt_object_libraries(AsanDynamicRuntimeThunk ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${arch} - SOURCES asan_globals_win.cpp - asan_win_dynamic_runtime_thunk.cpp + SOURCES ${ASAN_DYNAMIC_RUNTIME_THUNK_SOURCES} CFLAGS ${ASAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS}) @@ -361,12 +343,35 @@ else() STATIC ARCHS ${arch} OBJECT_LIBS AsanDynamicRuntimeThunk - UbsanDynamicRuntimeThunk - SancovDynamicRuntimeThunk - SanitizerCommonDynamicRuntimeThunk + UbsanRuntimeThunk + SancovRuntimeThunk + SanitizerRuntimeThunk CFLAGS ${ASAN_CFLAGS} ${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 ${ASAN_DYNAMIC_CFLAGS} ${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 ${ASAN_DYNAMIC_CFLAGS} ${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 2398984332321..56deb1b0d082b 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 19af88ab12b40..8267f07b9cce4 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_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp index 7e1d04c36dd58..3278f07219876 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) { - return _msize(ptr); -} +__declspec(noinline) size_t _msize_base(void *ptr) { return _msize(ptr); } -ALLOCATION_FUNCTION_ATTRIBUTE -void free(void *ptr) { +__declspec(noinline) void free(void *ptr) { GET_STACK_TRACE_FREE; return asan_free(ptr, &stack, FROM_MALLOC); } -ALLOCATION_FUNCTION_ATTRIBUTE -void _free_dbg(void *ptr, int) { - free(ptr); -} +__declspec(noinline) void _free_dbg(void *ptr, int) { free(ptr); } -ALLOCATION_FUNCTION_ATTRIBUTE -void _free_base(void *ptr) { - free(ptr); -} +__declspec(noinline) void _free_base(void *ptr) { free(ptr); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *malloc(size_t size) { +__declspec(noinline) void *malloc(size_t size) { GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_malloc_base(size_t size) { - return malloc(size); -} +__declspec(noinline) void *_malloc_base(size_t size) { return malloc(size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_malloc_dbg(size_t size, int, const char *, int) { +__declspec(noinline) void *_malloc_dbg(size_t size, int, const char *, int) { return malloc(size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *calloc(size_t nmemb, size_t size) { +__declspec(noinline) void *calloc(size_t nmemb, size_t size) { GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_calloc_base(size_t nmemb, size_t size) { +__declspec(noinline) void *_calloc_base(size_t nmemb, size_t size) { return calloc(nmemb, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) { +__declspec(noinline) void *_calloc_dbg(size_t nmemb, size_t size, int, + const char *, int) { return calloc(nmemb, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) { +__declspec(noinline) void *_calloc_impl(size_t nmemb, size_t size, + int *errno_tmp) { return calloc(nmemb, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *realloc(void *ptr, size_t size) { +__declspec(noinline) void *realloc(void *ptr, size_t size) { GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_realloc_dbg(void *ptr, size_t size, int) { +__declspec(noinline) void *_realloc_dbg(void *ptr, size_t size, int) { UNREACHABLE("_realloc_dbg should not exist!"); return 0; } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_realloc_base(void *ptr, size_t size) { +__declspec(noinline) void *_realloc_base(void *ptr, size_t size) { return realloc(ptr, size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_recalloc(void *p, size_t n, size_t elem_size) { +__declspec(noinline) void *_recalloc(void *p, size_t n, size_t elem_size) { if (!p) return calloc(n, elem_size); const size_t size = n * elem_size; @@ -166,23 +138,41 @@ void *_recalloc(void *p, size_t n, size_t elem_size) { return new_alloc; } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_recalloc_base(void *p, size_t n, size_t elem_size) { +__declspec(noinline) void *_recalloc_base(void *p, size_t n, size_t elem_size) { return _recalloc(p, n, elem_size); } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_expand(void *memblock, size_t size) { +__declspec(noinline) void *_expand(void *memblock, size_t size) { // _expand is used in realloc-like functions to resize the buffer if possible. // We don't want memory to stand still while resizing buffers, so return 0. return 0; } -ALLOCATION_FUNCTION_ATTRIBUTE -void *_expand_dbg(void *memblock, size_t size) { +__declspec(noinline) void *_expand_dbg(void *memblock, size_t size) { return _expand(memblock, size); } +__declspec(dllexport) size_t __cdecl __asan_msize(void *ptr) { + return _msize(ptr); +} +__declspec(dllexport) void __cdecl __asan_free(void *const ptr) { free(ptr); } +__declspec(dllexport) void *__cdecl __asan_malloc(const size_t size) { + return malloc(size); +} +__declspec(dllexport) void *__cdecl __asan_calloc(const size_t nmemb, + const size_t size) { + return calloc(nmemb, size); +} +__declspec(dllexport) void *__cdecl __asan_realloc(void *const ptr, + const size_t size) { + return realloc(ptr, size); +} +__declspec(dllexport) void *__cdecl __asan_recalloc(void *const ptr, + const size_t nmemb, + const size_t size) { + return _recalloc(ptr, nmemb, size); +} + // TODO(timurrrr): Might want to add support for _aligned_* allocation // functions to detect a bit more bugs. Those functions seem to wrap malloc(). @@ -487,7 +477,6 @@ static void TryToOverrideFunction(const char *fname, uptr new_func) { } void ReplaceSystemMalloc() { -#if defined(ASAN_DYNAMIC) TryToOverrideFunction("free", (uptr)free); TryToOverrideFunction("_free_base", (uptr)free); TryToOverrideFunction("malloc", (uptr)malloc); @@ -543,8 +532,6 @@ void ReplaceSystemMalloc() { // allocation API will be directed to ASan's heap. We don't currently // intercept all calls to HeapAlloc. If we did, we would have to check on // HeapFree whether the pointer came from ASan of from the system. - -#endif // defined(ASAN_DYNAMIC) } } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp new file mode 100644 index 0000000000000..abf515b77c4a9 --- /dev/null +++ b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp @@ -0,0 +1,229 @@ +//===-- asan_malloc_win_thunk.cpp +//-----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Windows-specific malloc interception. +// This is included statically for projects statically linking +// with the C Runtime (/MT, /MTd) in order to provide ASAN-aware +// versions of the C allocation functions. +//===----------------------------------------------------------------------===// + +#ifdef SANITIZER_STATIC_RUNTIME_THUNK +# include "..\sanitizer_common\sanitizer_allocator_interface.h" +// #include "asan_win_thunk_common.h" + +// Preserve stack traces with noinline. +# define STATIC_MALLOC_INTERFACE __declspec(noinline) + +extern "C" { +__declspec(dllimport) size_t __cdecl __asan_msize(void *ptr); +__declspec(dllimport) void __cdecl __asan_free(void *const ptr); +__declspec(dllimport) void *__cdecl __asan_malloc(const size_t size); +__declspec(dllimport) void *__cdecl __asan_calloc(const size_t nmemb, + const size_t size); +__declspec(dllimport) void *__cdecl __asan_realloc(void *const ptr, + const size_t size); +__declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr, + const size_t nmemb, + const size_t size); + +// Avoid tailcall optimization to preserve stack frames. +# pragma optimize("", off) + +// _msize +STATIC_MALLOC_INTERFACE size_t _msize(void *ptr) { return __asan_msize(ptr); } + +STATIC_MALLOC_INTERFACE size_t _msize_base(void *ptr) { + return __asan_msize(ptr); +} + +STATIC_MALLOC_INTERFACE size_t _msize_dbg(void *ptr) { + return __asan_msize(ptr); +} + +// free +STATIC_MALLOC_INTERFACE void free(void *const ptr) { return __asan_free(ptr); } + +STATIC_MALLOC_INTERFACE void _free_base(void *const ptr) { + return __asan_free(ptr); +} + +STATIC_MALLOC_INTERFACE void _free_dbg(void *const ptr) { + return __asan_free(ptr); +} + +// malloc +STATIC_MALLOC_INTERFACE void *malloc(const size_t size) { + return __asan_malloc(size); +} + +STATIC_MALLOC_INTERFACE void *_malloc_base(const size_t size) { + return __asan_malloc(size); +} + +STATIC_MALLOC_INTERFACE void *_malloc_dbg(const size_t size) { + return __asan_malloc(size); +} + +// calloc +STATIC_MALLOC_INTERFACE void *calloc(const size_t nmemb, const size_t size) { + return __asan_calloc(nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_calloc_base(const size_t nmemb, + const size_t size) { + return __asan_calloc(nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_calloc_impl(const size_t nmemb, + const size_t size, + int *const errno_tmp) { + // Provided by legacy msvcrt. + (void)errno_tmp; + + return __asan_calloc(nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_calloc_dbg(const size_t nmemb, const size_t size, + int, const char *, int) { + return __asan_calloc(nmemb, size); +} + +// realloc +STATIC_MALLOC_INTERFACE void *realloc(void *const ptr, const size_t size) { + return __asan_realloc(ptr, size); +} + +STATIC_MALLOC_INTERFACE void *_realloc_base(void *const ptr, + const size_t size) { + return __asan_realloc(ptr, size); +} + +STATIC_MALLOC_INTERFACE void *_realloc_dbg(void *const ptr, const size_t size, + int, const char *, int) { + return __asan_realloc(ptr, size); +} + +// recalloc +STATIC_MALLOC_INTERFACE void *_recalloc(void *const ptr, const size_t nmemb, + const size_t size) { + return __asan_recalloc(ptr, nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_recalloc_base(void *const ptr, + const size_t nmemb, + const size_t size) { + return __asan_recalloc(ptr, nmemb, size); +} + +STATIC_MALLOC_INTERFACE void *_recalloc_dbg(void *const ptr, const size_t nmemb, + const size_t size, int, + const char *, int) { + return __asan_recalloc(ptr, nmemb, size); +} + +// expand +STATIC_MALLOC_INTERFACE void *_expand(void *, size_t) { + // _expand is used in realloc-like functions to resize the buffer if possible. + // We don't want memory to stand still while resizing buffers, so return 0. + return nullptr; +} + +STATIC_MALLOC_INTERFACE void *_expand_dbg(void *, size_t, int, const char *, + int) { + return nullptr; +} + +// We need to provide symbols for all the debug CRT functions if we decide to +// provide any. Most of these functions make no sense under ASan and so we +// make them no-ops. +long _CrtSetBreakAlloc(long const) { return ~0; } + +void _CrtSetDbgBlockType(void *const, int const) { return; } + +typedef int(__cdecl *CRT_ALLOC_HOOK)(int, void *, size_t, int, long, + const unsigned char *, int); + +CRT_ALLOC_HOOK _CrtGetAllocHook() { return nullptr; } + +CRT_ALLOC_HOOK _CrtSetAllocHook(CRT_ALLOC_HOOK const hook) { return hook; } + +int _CrtCheckMemory() { return 1; } + +int _CrtSetDbgFlag(int const new_bits) { return new_bits; } + +typedef void (*CrtDoForAllClientObjectsCallback)(void *, void *); + +void _CrtDoForAllClientObjects(CrtDoForAllClientObjectsCallback const, + void *const) { + return; +} + +int _CrtIsValidPointer(void const *const p, unsigned int const, int const) { + return p != nullptr; +} + +int _CrtIsValidHeapPointer(void const *const block) { + if (!block) { + return 0; + } + + return __sanitizer_get_ownership(block); +} + +int _CrtIsMemoryBlock(void const *const, unsigned const, long *const, + char **const, int *const) { + return 0; +} + +int _CrtReportBlockType(void const *const) { return -1; } + +typedef void(__cdecl *CRT_DUMP_CLIENT)(void *, size_t); + +CRT_DUMP_CLIENT _CrtGetDumpClient() { return nullptr; } + +CRT_DUMP_CLIENT _CrtSetDumpClient(CRT_DUMP_CLIENT new_client) { + return new_client; +} + +void _CrtMemCheckpoint(void *const) { return; } + +int _CrtMemDifference(void *const, void const *const, void const *const) { + return 0; +} + +void _CrtMemDumpAllObjectsSince(void const *const) { return; } + +int _CrtDumpMemoryLeaks() { return 0; } + +void _CrtMemDumpStatistics(void const *const) { return; } + +int _crtDbgFlag{0}; +long _crtBreakAlloc{-1}; +CRT_DUMP_CLIENT _pfnDumpClient{nullptr}; + +int *__p__crtDbgFlag() { return &_crtDbgFlag; } + +long *__p__crtBreakAlloc() { return &_crtBreakAlloc; } + +// TODO: These were added upstream but conflict with definitions in ucrtbased. +// int _CrtDbgReport(int, const char *, int, const char *, const char *, ...) { +// ShowStatsAndAbort(); +// } +// +// int _CrtDbgReportW(int reportType, const wchar_t *, int, const wchar_t *, +// const wchar_t *, ...) { +// ShowStatsAndAbort(); +// } +// +// int _CrtSetReportMode(int, int) { return 0; } + +} // extern "C" +#endif // SANITIZER_STATIC_RUNTIME_THUNK diff --git a/compiler-rt/lib/asan/asan_win_common_runtime_thunk.cpp b/compiler-rt/lib/asan/asan_win_common_runtime_thunk.cpp new file mode 100644 index 0000000000000..d2c9e66c31337 --- /dev/null +++ b/compiler-rt/lib/asan/asan_win_common_runtime_thunk.cpp @@ -0,0 +1,112 @@ +//===-- asan_win_common_runtime_thunk.cpp --------------------------- -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines things that need to be present in the application modules +// to interact with the ASan DLL runtime correctly and can't be implemented +// using the default "import library" generated when linking the DLL. +// +// This includes: +// - Cloning shadow memory dynamic address from ASAN DLL +// - Creating weak aliases to default implementation imported from asan dll +// - Forwarding the detect_stack_use_after_return runtime option +// - installing a custom SEH handler +// +//===----------------------------------------------------------------------===// + +#if defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \ + defined(SANITIZER_STATIC_RUNTIME_THUNK) +# define SANITIZER_IMPORT_INTERFACE 1 +# define WIN32_LEAN_AND_MEAN +# include "asan_win_common_runtime_thunk.h" + +# include + +# include "sanitizer_common/sanitizer_win_defs.h" +# include "sanitizer_common/sanitizer_win_thunk_interception.h" + +// Define weak alias for all weak functions imported from asan dll. +# define INTERFACE_FUNCTION(Name) +# define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name) +# include "asan_interface.inc" + +//////////////////////////////////////////////////////////////////////////////// +// Define a copy of __asan_option_detect_stack_use_after_return that should be +// used when linking an MD runtime with a set of object files on Windows. +// +// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', +// so normally we would just dllimport it. Unfortunately, the dllimport +// attribute adds __imp_ prefix to the symbol name of a variable. +// Since in general we don't know if a given TU is going to be used +// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows +// just to work around this issue, let's clone the variable that is constant +// after initialization anyways. + +extern "C" { +__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); +int __asan_option_detect_stack_use_after_return; + +__declspec(dllimport) void *__asan_get_shadow_memory_dynamic_address(); +void *__asan_shadow_memory_dynamic_address; + +static void __asan_initialize_cloned_variables() { + __asan_option_detect_stack_use_after_return = + __asan_should_detect_stack_use_after_return(); + __asan_shadow_memory_dynamic_address = + __asan_get_shadow_memory_dynamic_address(); +} +} + +static int asan_thunk_init() { + __asan_initialize_cloned_variables(); + +# ifdef SANITIZER_STATIC_RUNTIME_THUNK + __asan_initialize_static_thunk(); +# endif + + return 0; +} + +static void WINAPI asan_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == DLL_PROCESS_ATTACH) { + asan_thunk_init(); + } +} + +// Our cloned variables must be initialized before C/C++ constructors. If TLS +// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB +// initializer is needed as a backup. +extern "C" __declspec(allocate(".CRT$XIB")) int (*__asan_thunk_init)() = + asan_thunk_init; +WIN_FORCE_LINK(__asan_thunk_init); + +extern "C" __declspec(allocate(".CRT$XLAB")) void(WINAPI *__asan_tls_init)( + void *, unsigned long, void *) = asan_thread_init; +WIN_FORCE_LINK(__asan_tls_init); + +//////////////////////////////////////////////////////////////////////////////// +// ASan SEH handling. +// We need to set the ASan-specific SEH handler at the end of CRT initialization +// of each module (see also asan_win.cpp). +extern "C" { +__declspec(dllimport) int __asan_set_seh_filter(); +static int SetSEHFilter() { return __asan_set_seh_filter(); } + +// Unfortunately, putting a pointer to __asan_set_seh_filter into +// __asan_intercept_seh gets optimized out, so we have to use an extra function. +extern "C" __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = + SetSEHFilter; +WIN_FORCE_LINK(__asan_seh_interceptor); +} + +WIN_FORCE_LINK(__asan_dso_reg_hook) + +#endif // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || + // defined(SANITIZER_STATIC_RUNTIME_THUNK) diff --git a/compiler-rt/lib/asan/asan_win_common_runtime_thunk.h b/compiler-rt/lib/asan/asan_win_common_runtime_thunk.h new file mode 100644 index 0000000000000..66285eb31ae99 --- /dev/null +++ b/compiler-rt/lib/asan/asan_win_common_runtime_thunk.h @@ -0,0 +1,38 @@ +//===-- asan_win_common_runtime_thunk.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines things that need to be present in the application modules +// to interact with the ASan DLL runtime correctly and can't be implemented +// using the default "import library" generated when linking the DLL. +// +//===----------------------------------------------------------------------===// + +#if defined(SANITIZER_STATIC_RUNTIME_THUNK) || \ + defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) +# include "sanitizer_common/sanitizer_win_defs.h" + +# pragma section(".CRT$XIB", long, \ + read) // C initializer (during C init before dyninit) +# pragma section(".CRT$XID", long, \ + read) // First C initializer after CRT initializers +# pragma section(".CRT$XCAB", long, \ + read) // First C++ initializer after startup initializers + +# pragma section(".CRT$XTW", long, read) // First ASAN globals terminator +# pragma section(".CRT$XTY", long, read) // Last ASAN globals terminator + +# pragma section(".CRT$XLAB", long, read) // First TLS initializer + +# ifdef SANITIZER_STATIC_RUNTIME_THUNK +extern "C" void __asan_initialize_static_thunk(); +# endif + +#endif // defined(SANITIZER_STATIC_RUNTIME_THUNK) || + // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) \ No newline at end of file diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cpp b/compiler-rt/lib/asan/asan_win_dll_thunk.cpp deleted file mode 100644 index 35871a942a7a1..0000000000000 --- a/compiler-rt/lib/asan/asan_win_dll_thunk.cpp +++ /dev/null @@ -1,165 +0,0 @@ -//===-- asan_win_dll_thunk.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -// This file defines a family of thunks that should be statically linked into -// the DLLs that have ASan instrumentation in order to delegate the calls to the -// shared runtime that lives in the main binary. -// See https://github.com/google/sanitizers/issues/209 for the details. -//===----------------------------------------------------------------------===// - -#ifdef SANITIZER_DLL_THUNK -#include "asan_init_version.h" -#include "interception/interception.h" -#include "sanitizer_common/sanitizer_win_defs.h" -#include "sanitizer_common/sanitizer_win_dll_thunk.h" -#include "sanitizer_common/sanitizer_platform_interceptors.h" - -// ASan own interface functions. -#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "asan_interface.inc" - -// Memory allocation functions. -INTERCEPT_WRAP_V_W(free) -INTERCEPT_WRAP_V_W(_free_base) -INTERCEPT_WRAP_V_WW(_free_dbg) - -INTERCEPT_WRAP_W_W(malloc) -INTERCEPT_WRAP_W_W(_malloc_base) -INTERCEPT_WRAP_W_WWWW(_malloc_dbg) - -INTERCEPT_WRAP_W_WW(calloc) -INTERCEPT_WRAP_W_WW(_calloc_base) -INTERCEPT_WRAP_W_WWWWW(_calloc_dbg) -INTERCEPT_WRAP_W_WWW(_calloc_impl) - -INTERCEPT_WRAP_W_WW(realloc) -INTERCEPT_WRAP_W_WW(_realloc_base) -INTERCEPT_WRAP_W_WWW(_realloc_dbg) -INTERCEPT_WRAP_W_WWW(_recalloc) -INTERCEPT_WRAP_W_WWW(_recalloc_base) - -INTERCEPT_WRAP_W_W(_msize) -INTERCEPT_WRAP_W_W(_msize_base) -INTERCEPT_WRAP_W_W(_expand) -INTERCEPT_WRAP_W_W(_expand_dbg) - -// TODO(timurrrr): Might want to add support for _aligned_* allocation -// functions to detect a bit more bugs. Those functions seem to wrap malloc(). - -// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cpp) - -# if defined(_MSC_VER) && !defined(__clang__) -// Disable warnings such as: 'void memchr(void)': incorrect number of arguments -// for intrinsic function, expected '3' arguments. -# pragma warning(push) -# pragma warning(disable : 4392) -# endif - -INTERCEPT_LIBRARY_FUNCTION(atoi); -INTERCEPT_LIBRARY_FUNCTION(atol); -INTERCEPT_LIBRARY_FUNCTION(atoll); -INTERCEPT_LIBRARY_FUNCTION(frexp); -INTERCEPT_LIBRARY_FUNCTION(longjmp); -#if SANITIZER_INTERCEPT_MEMCHR -INTERCEPT_LIBRARY_FUNCTION(memchr); -#endif -INTERCEPT_LIBRARY_FUNCTION(memcmp); -INTERCEPT_LIBRARY_FUNCTION(memcpy); -INTERCEPT_LIBRARY_FUNCTION(memmove); -INTERCEPT_LIBRARY_FUNCTION(memset); -INTERCEPT_LIBRARY_FUNCTION(strcat); -INTERCEPT_LIBRARY_FUNCTION(strchr); -INTERCEPT_LIBRARY_FUNCTION(strcmp); -INTERCEPT_LIBRARY_FUNCTION(strcpy); -INTERCEPT_LIBRARY_FUNCTION(strcspn); -INTERCEPT_LIBRARY_FUNCTION(_strdup); -INTERCEPT_LIBRARY_FUNCTION(strlen); -INTERCEPT_LIBRARY_FUNCTION(strncat); -INTERCEPT_LIBRARY_FUNCTION(strncmp); -INTERCEPT_LIBRARY_FUNCTION(strncpy); -INTERCEPT_LIBRARY_FUNCTION(strnlen); -INTERCEPT_LIBRARY_FUNCTION(strpbrk); -INTERCEPT_LIBRARY_FUNCTION(strrchr); -INTERCEPT_LIBRARY_FUNCTION(strspn); -INTERCEPT_LIBRARY_FUNCTION(strstr); -INTERCEPT_LIBRARY_FUNCTION(strtok); -INTERCEPT_LIBRARY_FUNCTION(strtol); -INTERCEPT_LIBRARY_FUNCTION(strtoll); -INTERCEPT_LIBRARY_FUNCTION(wcslen); -INTERCEPT_LIBRARY_FUNCTION(wcsnlen); - -# if defined(_MSC_VER) && !defined(__clang__) -# pragma warning(pop) -# endif - -#ifdef _WIN64 -INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler); -#else -INTERCEPT_LIBRARY_FUNCTION(_except_handler3); -// _except_handler4 checks -GS cookie which is different for each module, so we -// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4). -INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { - __asan_handle_no_return(); - return REAL(_except_handler4)(a, b, c, d); -} -#endif - -// Windows specific functions not included in asan_interface.inc. -INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return) -INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address) -INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter) - -using namespace __sanitizer; - -extern "C" { -int __asan_option_detect_stack_use_after_return; -uptr __asan_shadow_memory_dynamic_address; -} // extern "C" - -static int asan_dll_thunk_init() { - typedef void (*fntype)(); - static fntype fn = 0; - // asan_dll_thunk_init is expected to be called by only one thread. - if (fn) return 0; - - // Ensure all interception was executed. - __dll_thunk_init(); - - fn = (fntype) dllThunkGetRealAddrOrDie("__asan_init"); - fn(); - __asan_option_detect_stack_use_after_return = - (__asan_should_detect_stack_use_after_return() != 0); - __asan_shadow_memory_dynamic_address = - (uptr)__asan_get_shadow_memory_dynamic_address(); - -#ifndef _WIN64 - INTERCEPT_FUNCTION(_except_handler4); -#endif - // In DLLs, the callbacks are expected to return 0, - // otherwise CRT initialization fails. - return 0; -} - -#pragma section(".CRT$XIB", long, read) -__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = asan_dll_thunk_init; - -static void WINAPI asan_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == /*DLL_PROCESS_ATTACH=*/1) asan_dll_thunk_init(); -} - -#pragma section(".CRT$XLAB", long, read) -__declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *, - unsigned long, void *) = asan_thread_init; - -WIN_FORCE_LINK(__asan_dso_reg_hook) - -#endif // SANITIZER_DLL_THUNK diff --git a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cpp b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cpp index f0b5ec9eef7f9..421fe651b7d91 100644 --- a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cpp +++ b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cpp @@ -8,76 +8,17 @@ // // This file is a part of AddressSanitizer, an address sanity checker. // -// This file defines things that need to be present in the application modules -// to interact with the ASan DLL runtime correctly and can't be implemented -// using the default "import library" generated when linking the DLL RTL. -// -// This includes: -// - creating weak aliases to default implementation imported from asan dll. -// - forwarding the detect_stack_use_after_return runtime option -// - working around deficiencies of the MD runtime -// - installing a custom SEH handler +// This file defines things that need to be present for application modules +// that are dynamic linked with the C Runtime. // //===----------------------------------------------------------------------===// #ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK -#define SANITIZER_IMPORT_INTERFACE 1 -#include "sanitizer_common/sanitizer_win_defs.h" -#define WIN32_LEAN_AND_MEAN -#include - -// Define weak alias for all weak functions imported from asan dll. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) -#include "asan_interface.inc" - -// First, declare CRT sections we'll be using in this file -#pragma section(".CRT$XIB", long, read) -#pragma section(".CRT$XID", long, read) -#pragma section(".CRT$XCAB", long, read) -#pragma section(".CRT$XTW", long, read) -#pragma section(".CRT$XTY", long, read) -#pragma section(".CRT$XLAB", long, read) - -//////////////////////////////////////////////////////////////////////////////// -// Define a copy of __asan_option_detect_stack_use_after_return that should be -// used when linking an MD runtime with a set of object files on Windows. -// -// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', -// so normally we would just dllimport it. Unfortunately, the dllimport -// attribute adds __imp_ prefix to the symbol name of a variable. -// Since in general we don't know if a given TU is going to be used -// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows -// just to work around this issue, let's clone the variable that is constant -// after initialization anyways. -extern "C" { -__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); -int __asan_option_detect_stack_use_after_return; - -__declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address(); -void* __asan_shadow_memory_dynamic_address; -} - -static int InitializeClonedVariables() { - __asan_option_detect_stack_use_after_return = - __asan_should_detect_stack_use_after_return(); - __asan_shadow_memory_dynamic_address = - __asan_get_shadow_memory_dynamic_address(); - return 0; -} - -static void NTAPI asan_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables(); -} +# define WIN32_LEAN_AND_MEAN +# include -// Our cloned variables must be initialized before C/C++ constructors. If TLS -// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB -// initializer is needed as a backup. -__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() = - InitializeClonedVariables; -__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *, - unsigned long, void *) = asan_thread_init; +# include "asan_win_common_runtime_thunk.h" +# include "sanitizer_common/sanitizer_win_defs.h" //////////////////////////////////////////////////////////////////////////////// // For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL @@ -88,43 +29,26 @@ __declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *, // using atexit() that calls a small subset of C terminators // where LLVM global_dtors is placed. Fingers crossed, no other C terminators // are there. -extern "C" int __cdecl atexit(void (__cdecl *f)(void)); +extern "C" int __cdecl atexit(void(__cdecl *f)(void)); extern "C" void __cdecl _initterm(void *a, void *b); namespace { -__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0; -__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0; +__declspec(allocate(".CRT$XTW")) void *before_global_dtors = 0; +__declspec(allocate(".CRT$XTY")) void *after_global_dtors = 0; void UnregisterGlobals() { _initterm(&before_global_dtors, &after_global_dtors); } -int ScheduleUnregisterGlobals() { - return atexit(UnregisterGlobals); -} +int ScheduleUnregisterGlobals() { return atexit(UnregisterGlobals); } } // namespace // We need to call 'atexit(UnregisterGlobals);' as early as possible, but after // atexit() is initialized (.CRT$XIC). As this is executed before C++ // initializers (think ctors for globals), UnregisterGlobals gets executed after // dtors for C++ globals. -__declspec(allocate(".CRT$XID")) -int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; - -//////////////////////////////////////////////////////////////////////////////// -// ASan SEH handling. -// We need to set the ASan-specific SEH handler at the end of CRT initialization -// of each module (see also asan_win.cpp). -extern "C" { -__declspec(dllimport) int __asan_set_seh_filter(); -static int SetSEHFilter() { return __asan_set_seh_filter(); } - -// Unfortunately, putting a pointer to __asan_set_seh_filter into -// __asan_intercept_seh gets optimized out, so we have to use an extra function. -__declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() = - SetSEHFilter; -} - -WIN_FORCE_LINK(__asan_dso_reg_hook) +extern "C" __declspec(allocate(".CRT$XID")) int ( + *__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; +WIN_FORCE_LINK(__asan_schedule_unregister_globals) -#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK +#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK diff --git a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp new file mode 100644 index 0000000000000..dec50a5e1d4d9 --- /dev/null +++ b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp @@ -0,0 +1,110 @@ +//===-- asan_win_static_runtime_thunk.cpp ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines a family of thunks that should be statically linked into +// modules that are statically linked with the C Runtime in order to delegate +// the calls to the ASAN runtime DLL. +// See https://github.com/google/sanitizers/issues/209 for the details. +//===----------------------------------------------------------------------===// + +#ifdef SANITIZER_STATIC_RUNTIME_THUNK +# include "asan_init_version.h" +# include "asan_interface_internal.h" +# include "asan_win_common_runtime_thunk.h" +# include "sanitizer_common/sanitizer_platform_interceptors.h" +# include "sanitizer_common/sanitizer_win_defs.h" +# include "sanitizer_common/sanitizer_win_thunk_interception.h" + +# if defined(_MSC_VER) && !defined(__clang__) +// Disable warnings such as: 'void memchr(void)': incorrect number of arguments +// for intrinsic function, expected '3' arguments. +# pragma warning(push) +# pragma warning(disable : 4392) +# endif + +# define INTERCEPT_LIBRARY_FUNCTION_ASAN(X) \ + INTERCEPT_LIBRARY_FUNCTION(X, "__asan_wrap_" #X) + +INTERCEPT_LIBRARY_FUNCTION_ASAN(atoi); +INTERCEPT_LIBRARY_FUNCTION_ASAN(atol); +INTERCEPT_LIBRARY_FUNCTION_ASAN(atoll); +INTERCEPT_LIBRARY_FUNCTION_ASAN(frexp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(longjmp); +# if SANITIZER_INTERCEPT_MEMCHR +INTERCEPT_LIBRARY_FUNCTION_ASAN(memchr); +# endif +INTERCEPT_LIBRARY_FUNCTION_ASAN(memcmp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(memcpy); +# ifndef _WIN64 +// memmove and memcpy share an implementation on amd64 +INTERCEPT_LIBRARY_FUNCTION_ASAN(memmove); +# endif +INTERCEPT_LIBRARY_FUNCTION_ASAN(memset); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strchr); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcmp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcpy); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strcspn); +INTERCEPT_LIBRARY_FUNCTION_ASAN(_strdup); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strlen); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strncat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strncmp); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strncpy); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strnlen); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strpbrk); +// INTERCEPT_LIBRARY_FUNCTION_ASAN(strrchr); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strspn); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strstr); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strtok); +INTERCEPT_LIBRARY_FUNCTION_ASAN(strtol); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcslen); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsnlen); + +# if defined(_MSC_VER) && !defined(__clang__) +# pragma warning(pop) +# endif + +# ifdef _WIN64 +INTERCEPT_LIBRARY_FUNCTION_ASAN(__C_specific_handler); +# else +extern "C" void abort(); +INTERCEPT_LIBRARY_FUNCTION_ASAN(_except_handler3); +// _except_handler4 checks -GS cookie which is different for each module, so we +// can't use INTERCEPT_LIBRARY_FUNCTION_ASAN(_except_handler4), need to apply +// manually +extern "C" int _except_handler4(void *, void *, void *, void *); +static int (*real_except_handler4)(void *, void *, void *, + void *) = &_except_handler4; +static int intercept_except_handler4(void *a, void *b, void *c, void *d) { + __asan_handle_no_return(); + return real_except_handler4(a, b, c, d); +} +# endif + +// Windows specific functions not included in asan_interface.inc. +// INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return) +// INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address) +// INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter) + +extern "C" void __asan_initialize_static_thunk() { +# ifndef _WIN64 + if (real_except_handler4 == &_except_handler4) { + // Single threaded, no need for synchronization. + if (!__sanitizer_override_function_by_addr( + reinterpret_cast<__sanitizer::uptr>(&intercept_except_handler4), + reinterpret_cast<__sanitizer::uptr>(&_except_handler4), + reinterpret_cast<__sanitizer::uptr*>(&real_except_handler4))) { + abort(); + } + } +# endif +} + +#endif // SANITIZER_DLL_THUNK diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt index bda47bd7fd6a2..9c1db7caeb7b7 100644 --- a/compiler-rt/lib/asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/asan/tests/CMakeLists.txt @@ -203,7 +203,7 @@ function(add_asan_tests arch test_runtime) CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL SOURCES ${ASAN_INST_TEST_SOURCES} LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS} - -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames + -D_MT -D_DLL -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames ) else() diff --git a/compiler-rt/lib/profile/CMakeLists.txt b/compiler-rt/lib/profile/CMakeLists.txt index 45e5164891751..ef23492514898 100644 --- a/compiler-rt/lib/profile/CMakeLists.txt +++ b/compiler-rt/lib/profile/CMakeLists.txt @@ -111,6 +111,12 @@ if(COMPILER_RT_TARGET_HAS_UNAME) -DCOMPILER_RT_HAS_UNAME=1) endif() +if(MSVC) + # profile historically has only been supported with the static runtime + # on windows + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) +endif() + # We don't use the C++ Standard Library here, so avoid including it by mistake. append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ EXTRA_FLAGS) # XRay uses C++ standard library headers. diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index 66f2d259aa5fd..41c3888275a0f 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt @@ -42,6 +42,7 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_thread_registry.cpp sanitizer_type_traits.cpp sanitizer_win.cpp + sanitizer_win_interception.cpp ) set(SANITIZER_SOURCES @@ -206,8 +207,8 @@ set(SANITIZER_IMPL_HEADERS sanitizer_vector.h sanitizer_win.h sanitizer_win_defs.h - sanitizer_win_dll_thunk.h - sanitizer_win_weak_interception.h + sanitizer_win_interception.h + sanitizer_win_thunk_interception.h ) include_directories(..) @@ -301,57 +302,23 @@ add_compiler_rt_object_libraries(RTSanitizerCommonSymbolizerNoHooks DEFS ${SANITIZER_COMMON_DEFINITIONS}) if(WIN32) - add_compiler_rt_object_libraries(SanitizerCommonWeakInterception + set(RUNTIME_THUNK_CFLAGS -DSANITIZER_DYNAMIC_RUNTIME_THUNK -DSANITIZER_STATIC_RUNTIME_THUNK) + append_list_if(MSVC /Zl RUNTIME_THUNK_CFLAGS) + add_compiler_rt_object_libraries(SanitizerRuntimeThunk ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} SOURCES - sanitizer_win_weak_interception.cpp - CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DYNAMIC - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - add_compiler_rt_object_libraries(SancovWeakInterception - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES - sanitizer_coverage_win_weak_interception.cpp - CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DYNAMIC - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - - add_compiler_rt_object_libraries(SanitizerCommonDllThunk - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES - sanitizer_win_dll_thunk.cpp - CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DLL_THUNK - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - add_compiler_rt_object_libraries(SancovDllThunk - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES - sanitizer_coverage_win_dll_thunk.cpp - sanitizer_coverage_win_sections.cpp - CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DLL_THUNK + sanitizer_win_thunk_interception.cpp + CFLAGS ${SANITIZER_CFLAGS} ${RUNTIME_THUNK_CFLAGS} DEFS ${SANITIZER_COMMON_DEFINITIONS}) - set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_DYNAMIC_RUNTIME_THUNK") - if(MSVC) - list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-Zl") - elseif(CMAKE_C_COMPILER_ID MATCHES Clang) - list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-nodefaultlibs") - endif() - add_compiler_rt_object_libraries(SanitizerCommonDynamicRuntimeThunk - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES - sanitizer_win_dynamic_runtime_thunk.cpp - CFLAGS ${SANITIZER_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS} - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - add_compiler_rt_object_libraries(SancovDynamicRuntimeThunk + add_compiler_rt_object_libraries(SancovRuntimeThunk ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} SOURCES - sanitizer_coverage_win_dynamic_runtime_thunk.cpp + sanitizer_coverage_win_runtime_thunk.cpp sanitizer_coverage_win_sections.cpp - CFLAGS ${SANITIZER_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS} + CFLAGS ${SANITIZER_CFLAGS} ${RUNTIME_THUNK_CFLAGS} DEFS ${SANITIZER_COMMON_DEFINITIONS}) endif() diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc index 557207fe62ac6..11f1d963bd6f4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc @@ -50,3 +50,9 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_malloc_hook) INTERFACE_FUNCTION(__sanitizer_internal_memcpy) INTERFACE_FUNCTION(__sanitizer_internal_memmove) INTERFACE_FUNCTION(__sanitizer_internal_memset) + +#if SANITIZER_WINDOWS +INTERFACE_FUNCTION(__sanitizer_override_function) +INTERFACE_FUNCTION(__sanitizer_override_function_by_addr) +INTERFACE_FUNCTION(__sanitizer_register_weak_function) +#endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp deleted file mode 100644 index d0bf8a4556436..0000000000000 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- sanitizer_coverage_win_dll_thunk.cpp ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a family of thunks that should be statically linked into -// the DLLs that have instrumentation in order to delegate the calls to the -// shared runtime that lives in the main binary. -// See https://github.com/google/sanitizers/issues/209 for the details. -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DLL_THUNK -#include "sanitizer_win_dll_thunk.h" -// Sanitizer Coverage interface functions. -#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_coverage_interface.inc" -#endif // SANITIZER_DLL_THUNK diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp similarity index 59% rename from compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp rename to compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp index 0bdf0c5aed418..281944643f216 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp @@ -1,4 +1,4 @@ -//===-- sanitizer_coverage_win_dynamic_runtime_thunk.cpp ------------------===// +//===-- sanitizer_coverage_win_runtime_thunk.cpp --------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,17 +10,20 @@ // to interact with Sanitizer Coverage, when it is included in a dll. // //===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK -#define SANITIZER_IMPORT_INTERFACE 1 -#include "sanitizer_win_defs.h" +#if defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \ + defined(SANITIZER_STATIC_RUNTIME_THUNK) +# define SANITIZER_IMPORT_INTERFACE 1 +# include "sanitizer_win_defs.h" +# include "sanitizer_win_thunk_interception.h" // Define weak alias for all weak functions imported from sanitizer coverage. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) -#include "sanitizer_coverage_interface.inc" -#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK +# define INTERFACE_FUNCTION(Name) +# define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name) +# include "sanitizer_coverage_interface.inc" +#endif // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || + // defined(SANITIZER_STATIC_RUNTIME_THUNK) namespace __sanitizer { // Add one, otherwise unused, external symbol to this object file so that the // Visual C++ linker includes it and reads the .drective section. void ForceWholeArchiveIncludeForSanCov() {} -} +} // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp deleted file mode 100644 index 55263981705fa..0000000000000 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//===-- sanitizer_coverage_win_weak_interception.cpp ----------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This module should be included in Sanitizer Coverage when it implemented as a -// shared library on Windows (dll), in order to delegate the calls of weak -// functions to the implementation in the main executable when a strong -// definition is provided. -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC -#include "sanitizer_win_weak_interception.h" -#include "sanitizer_interface_internal.h" -#include "sancov_flags.h" -// Check if strong definitions for weak functions are present in the main -// executable. If that is the case, override dll functions to point to strong -// implementations. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_coverage_interface.inc" -#endif // SANITIZER_DYNAMIC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp deleted file mode 100644 index 1562c161a7626..0000000000000 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===-- sanitizer_win_dll_thunk.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This file defines a family of thunks that should be statically linked into -// the DLLs that have instrumentation in order to delegate the calls to the -// shared runtime that lives in the main binary. -// See https://github.com/google/sanitizers/issues/209 for the details. -//===----------------------------------------------------------------------===// - -#ifdef SANITIZER_DLL_THUNK -#include "sanitizer_win_defs.h" -#include "sanitizer_win_dll_thunk.h" -#include "interception/interception.h" - -extern "C" { -void *WINAPI GetModuleHandleA(const char *module_name); -void abort(); -} - -namespace __sanitizer { -uptr dllThunkGetRealAddrOrDie(const char *name) { - uptr ret = - __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); - if (!ret) - abort(); - return ret; -} - -int dllThunkIntercept(const char* main_function, uptr dll_function) { - uptr wrapper = dllThunkGetRealAddrOrDie(main_function); - if (!__interception::OverrideFunction(dll_function, wrapper, 0)) - abort(); - return 0; -} - -int dllThunkInterceptWhenPossible(const char* main_function, - const char* default_function, uptr dll_function) { - uptr wrapper = __interception::InternalGetProcAddress( - (void *)GetModuleHandleA(0), main_function); - if (!wrapper) - wrapper = dllThunkGetRealAddrOrDie(default_function); - if (!__interception::OverrideFunction(dll_function, wrapper, 0)) - abort(); - return 0; -} -} // namespace __sanitizer - -// Include Sanitizer Common interface. -#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_common_interface.inc" - -#pragma section(".DLLTH$A", read) -#pragma section(".DLLTH$Z", read) - -typedef void (*DllThunkCB)(); -extern "C" { -__declspec(allocate(".DLLTH$A")) DllThunkCB __start_dll_thunk; -__declspec(allocate(".DLLTH$Z")) DllThunkCB __stop_dll_thunk; -} - -// Disable compiler warnings that show up if we declare our own version -// of a compiler intrinsic (e.g. strlen). -#pragma warning(disable: 4391) -#pragma warning(disable: 4392) - -extern "C" int __dll_thunk_init() { - static bool flag = false; - // __dll_thunk_init is expected to be called by only one thread. - if (flag) return 0; - flag = true; - - for (DllThunkCB *it = &__start_dll_thunk; it < &__stop_dll_thunk; ++it) - if (*it) - (*it)(); - - // In DLLs, the callbacks are expected to return 0, - // otherwise CRT initialization fails. - return 0; -} - -// We want to call dll_thunk_init before C/C++ initializers / constructors are -// executed, otherwise functions like memset might be invoked. -#pragma section(".CRT$XIB", long, read) -__declspec(allocate(".CRT$XIB")) int (*__dll_thunk_preinit)() = - __dll_thunk_init; - -static void WINAPI dll_thunk_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == /*DLL_PROCESS_ATTACH=*/1) __dll_thunk_init(); -} - -#pragma section(".CRT$XLAB", long, read) -__declspec(allocate(".CRT$XLAB")) void (WINAPI *__dll_thunk_tls_init)(void *, - unsigned long, void *) = dll_thunk_thread_init; - -#endif // SANITIZER_DLL_THUNK diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h deleted file mode 100644 index 639d91a2edaec..0000000000000 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h +++ /dev/null @@ -1,181 +0,0 @@ -//===-- sanitizer_win_dll_thunk.h -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This header provide helper macros to delegate calls to the shared runtime -// that lives in the main executable. It should be included to dll_thunks that -// will be linked to the dlls, when the sanitizer is a static library included -// in the main executable. -//===----------------------------------------------------------------------===// -#ifndef SANITIZER_WIN_DLL_THUNK_H -#define SANITIZER_WIN_DLL_THUNK_H -#include "sanitizer_internal_defs.h" - -namespace __sanitizer { -uptr dllThunkGetRealAddrOrDie(const char *name); - -int dllThunkIntercept(const char* main_function, uptr dll_function); - -int dllThunkInterceptWhenPossible(const char* main_function, - const char* default_function, uptr dll_function); -} - -extern "C" int __dll_thunk_init(); - -// ----------------- Function interception helper macros -------------------- // -// Override dll_function with main_function from main executable. -#define INTERCEPT_OR_DIE(main_function, dll_function) \ - static int intercept_##dll_function() { \ - return __sanitizer::dllThunkIntercept(main_function, (__sanitizer::uptr) \ - dll_function); \ - } \ - __pragma(section(".DLLTH$M", long, read)) \ - __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ - intercept_##dll_function; - -// Try to override dll_function with main_function from main executable. -// If main_function is not present, override dll_function with default_function. -#define INTERCEPT_WHEN_POSSIBLE(main_function, default_function, dll_function) \ - static int intercept_##dll_function() { \ - return __sanitizer::dllThunkInterceptWhenPossible(main_function, \ - default_function, (__sanitizer::uptr)dll_function); \ - } \ - __pragma(section(".DLLTH$M", long, read)) \ - __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \ - intercept_##dll_function; - -// -------------------- Function interception macros ------------------------ // -// Special case of hooks -- ASan own interface functions. Those are only called -// after __asan_init, thus an empty implementation is sufficient. -#define INTERCEPT_SANITIZER_FUNCTION(name) \ - extern "C" __declspec(noinline) void name() { \ - volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ - static const char function_name[] = #name; \ - for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ - prevent_icf ^= *ptr; \ - (void)prevent_icf; \ - __debugbreak(); \ - } \ - INTERCEPT_OR_DIE(#name, name) - -// Special case of hooks -- Weak functions, could be redefined in the main -// executable, but that is not necessary, so we shouldn't die if we can not find -// a reference. Instead, when the function is not present in the main executable -// we consider the default impl provided by asan library. -#define INTERCEPT_SANITIZER_WEAK_FUNCTION(name) \ - extern "C" __declspec(noinline) void name() { \ - volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \ - static const char function_name[] = #name; \ - for (const char* ptr = &function_name[0]; *ptr; ++ptr) \ - prevent_icf ^= *ptr; \ - (void)prevent_icf; \ - __debugbreak(); \ - } \ - INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name) - -// We can't define our own version of strlen etc. because that would lead to -// link-time or even type mismatch errors. Instead, we can declare a function -// just to be able to get its address. Me may miss the first few calls to the -// functions since it can be called before __dll_thunk_init, but that would lead -// to false negatives in the startup code before user's global initializers, -// which isn't a big deal. -#define INTERCEPT_LIBRARY_FUNCTION(name) \ - extern "C" void name(); \ - INTERCEPT_OR_DIE(STRINGIFY(WRAP(name)), name) - -// Use these macros for functions that could be called before __dll_thunk_init() -// is executed and don't lead to errors if defined (free, malloc, etc). -#define INTERCEPT_WRAP_V_V(name) \ - extern "C" void name() { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - fn(); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_V_W(name) \ - extern "C" void name(void *arg) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - fn(arg); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_V_WW(name) \ - extern "C" void name(void *arg1, void *arg2) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - fn(arg1, arg2); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_V_WWW(name) \ - extern "C" void name(void *arg1, void *arg2, void *arg3) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - fn(arg1, arg2, arg3); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_W_V(name) \ - extern "C" void *name() { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - return fn(); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_W_W(name) \ - extern "C" void *name(void *arg) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - return fn(arg); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_W_WW(name) \ - extern "C" void *name(void *arg1, void *arg2) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - return fn(arg1, arg2); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_W_WWW(name) \ - extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - return fn(arg1, arg2, arg3); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_W_WWWW(name) \ - extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - return fn(arg1, arg2, arg3, arg4); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_W_WWWWW(name) \ - extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ - void *arg5) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - return fn(arg1, arg2, arg3, arg4, arg5); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#define INTERCEPT_WRAP_W_WWWWWW(name) \ - extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ - void *arg5, void *arg6) { \ - typedef decltype(name) *fntype; \ - static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \ - return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ - } \ - INTERCEPT_OR_DIE(#name, name); - -#endif // SANITIZER_WIN_DLL_THUNK_H diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp deleted file mode 100644 index 87c032c6e61bc..0000000000000 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp +++ /dev/null @@ -1,26 +0,0 @@ -//===-- santizer_win_dynamic_runtime_thunk.cpp ----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines things that need to be present in the application modules -// to interact with Sanitizer Common, when it is included in a dll. -// -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK -#define SANITIZER_IMPORT_INTERFACE 1 -#include "sanitizer_win_defs.h" -// Define weak alias for all weak functions imported from sanitizer common. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) -#include "sanitizer_common_interface.inc" -#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK - -namespace __sanitizer { -// Add one, otherwise unused, external symbol to this object file so that the -// Visual C++ linker includes it and reads the .drective section. -void ForceWholeArchiveIncludeForSanitizerCommon() {} -} diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h new file mode 100644 index 0000000000000..808cd2f771fe1 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h @@ -0,0 +1,71 @@ +//===-- sanitizer_win_immortalize.h ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer, and interception. +// +// Windows-specific thread-safe and pre-CRT global initialization safe +// infrastructure to create an object whose destructor is never called. +//===----------------------------------------------------------------------===// +#if SANITIZER_WINDOWS +# pragma once +// Requires including sanitizer_placement_new.h (which is not allowed to be +// included in headers). + +# include "sanitizer_win_defs.h" +// These types are required to satisfy XFG which requires that the names of the +// types for indirect calls to be correct as well as the name of the original +// type for any typedefs. + +// TODO: There must be a better way to do this +# ifndef _WINDOWS_ +typedef void* PVOID; +typedef int BOOL; +typedef union _RTL_RUN_ONCE { + PVOID ptr; +} INIT_ONCE, *PINIT_ONCE; + +extern "C" { +__declspec(dllimport) int WINAPI InitOnceExecuteOnce( + PINIT_ONCE, BOOL(WINAPI*)(PINIT_ONCE, PVOID, PVOID*), void*, void*); +} +# endif + +namespace __sanitizer { +template +BOOL WINAPI immortalize_impl(PINIT_ONCE, PVOID storage_ptr, PVOID*) noexcept { + // Ty must provide a placement new operator + new (storage_ptr) Ty(); + return 1; +} + +template +BOOL WINAPI immortalize_impl(PINIT_ONCE, PVOID storage_ptr, + PVOID* param) noexcept { + // Ty must provide a placement new operator + new (storage_ptr) Ty(*((Arg*)param)); + return 1; +} + +template +Ty& immortalize() { // return a reference to an object that will live forever + static INIT_ONCE flag; + alignas(Ty) static unsigned char storage[sizeof(Ty)]; + InitOnceExecuteOnce(&flag, immortalize_impl, &storage, nullptr); + return reinterpret_cast(storage); +} + +template +Ty& immortalize( + Arg arg) { // return a reference to an object that will live forever + static INIT_ONCE flag; + alignas(Ty) static unsigned char storage[sizeof(Ty)]; + InitOnceExecuteOnce(&flag, immortalize_impl, &storage, &arg); + return reinterpret_cast(storage); +} +} // namespace __sanitizer +#endif // SANITIZER_WINDOWS diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp new file mode 100644 index 0000000000000..75a1545d00d8b --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp @@ -0,0 +1,156 @@ +//===-- sanitizer_win_interception.cpp -------------------- --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Windows-specific export surface to provide interception for parts of the +// runtime that are always statically linked, both for overriding user-defined +// functions as well as registering weak functions that the ASAN runtime should +// use over defaults. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS +# include + +# include "interception/interception.h" +# include "sanitizer_addrhashmap.h" +# include "sanitizer_common.h" +# include "sanitizer_internal_defs.h" +# include "sanitizer_placement_new.h" +# include "sanitizer_win_immortalize.h" +# include "sanitizer_win_interception.h" + +using namespace __sanitizer; + +extern "C" void *__ImageBase; + +namespace __sanitizer { + +static uptr GetSanitizerDllExport(const char *export_name) { + const uptr function_address = + __interception::InternalGetProcAddress(&__ImageBase, export_name); + if (function_address == 0) { + Report("ERROR: Failed to find sanitizer DLL export '%s'\n", export_name); + CHECK("Failed to find sanitizer DLL export" && 0); + } + return function_address; +} + +struct WeakCallbackList { + explicit constexpr WeakCallbackList(RegisterWeakFunctionCallback cb) + : callback(cb), next(nullptr) {} + + static void *operator new(size_t size) { return InternalAlloc(size); } + + static void operator delete(void *p) { InternalFree(p); } + + RegisterWeakFunctionCallback callback; + WeakCallbackList *next; +}; +using WeakCallbackMap = AddrHashMap; + +static WeakCallbackMap *GetWeakCallbackMap() { + return &immortalize(); +} + +void AddRegisterWeakFunctionCallback(uptr export_address, + RegisterWeakFunctionCallback cb) { + WeakCallbackMap::Handle h_find_or_create(GetWeakCallbackMap(), export_address, + false, true); + CHECK(h_find_or_create.exists()); + if (h_find_or_create.created()) { + *h_find_or_create = new WeakCallbackList(cb); + } else { + (*h_find_or_create)->next = new WeakCallbackList(cb); + } +} + +static void RunWeakFunctionCallbacks(uptr export_address) { + WeakCallbackMap::Handle h_find(GetWeakCallbackMap(), export_address, false, + false); + if (!h_find.exists()) { + return; + } + + WeakCallbackList *list = *h_find; + do { + list->callback(); + } while ((list = list->next)); +} + +} // namespace __sanitizer + +extern "C" __declspec(dllexport) bool __cdecl __sanitizer_override_function( + const char *export_name, const uptr user_function, + uptr *const old_user_function) { + CHECK(export_name); + CHECK(user_function); + + const uptr sanitizer_function = GetSanitizerDllExport(export_name); + + const bool function_overridden = __interception::OverrideFunction( + user_function, sanitizer_function, old_user_function); + if (!function_overridden) { + Report( + "ERROR: Failed to override local function at '%p' with sanitizer " + "function '%s'\n", + user_function, export_name); + CHECK("Failed to replace local function with sanitizer version." && 0); + } + + return function_overridden; +} + +extern "C" + __declspec(dllexport) bool __cdecl __sanitizer_override_function_by_addr( + const uptr source_function, const uptr target_function, + uptr *const old_target_function) { + CHECK(source_function); + CHECK(target_function); + + const bool function_overridden = __interception::OverrideFunction( + target_function, source_function, old_target_function); + if (!function_overridden) { + Report( + "ERROR: Failed to override function at '%p' with function at " + "'%p'\n", + target_function, source_function); + CHECK("Failed to apply function override." && 0); + } + + return function_overridden; +} + +extern "C" + __declspec(dllexport) bool __cdecl __sanitizer_register_weak_function( + const char *export_name, const uptr user_function, + uptr *const old_user_function) { + CHECK(export_name); + CHECK(user_function); + + const uptr sanitizer_function = GetSanitizerDllExport(export_name); + + const bool function_overridden = __interception::OverrideFunction( + sanitizer_function, user_function, old_user_function); + if (!function_overridden) { + Report( + "ERROR: Failed to register local function at '%p' to be used in " + "place of sanitizer function '%s'\n.", + user_function, export_name); + CHECK("Failed to register weak function." && 0); + } + + // Note that thread-safety of RunWeakFunctionCallbacks in InitializeFlags + // depends on __sanitizer_register_weak_functions being called during the + // loader lock. + RunWeakFunctionCallbacks(sanitizer_function); + + return function_overridden; +} + +#endif // SANITIZER_WINDOWS diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.h new file mode 100644 index 0000000000000..70ae3d6bf31f2 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.h @@ -0,0 +1,32 @@ +//===-- sanitizer_win_interception.h ---------------------- --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Windows-specific export surface to provide interception for parts of the +// runtime that are always statically linked, both for overriding user-defined +// functions as well as registering weak functions that the ASAN runtime should +// use over defaults. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_WIN_INTERCEPTION_H +#define SANITIZER_WIN_INTERCEPTION_H + +#include "sanitizer_platform.h" +#if SANITIZER_WINDOWS + +# include "sanitizer_common.h" +# include "sanitizer_internal_defs.h" + +namespace __sanitizer { +using RegisterWeakFunctionCallback = void (*)(); +void AddRegisterWeakFunctionCallback(uptr export_address, + RegisterWeakFunctionCallback cb); +} // namespace __sanitizer + +#endif // SANITIZER_WINDOWS +#endif // SANITIZER_WIN_INTERCEPTION_H \ No newline at end of file diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.cpp new file mode 100644 index 0000000000000..13db8869abadd --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.cpp @@ -0,0 +1,110 @@ +//===-- sanitizer_win_thunk_interception.cpp ----------------------- -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines things that need to be present in the application modules +// to interact with sanitizer DLL correctly and cannot be implemented using the +// default "import library" generated when linking the DLL. +// +// This includes the common infrastructure required to intercept local functions +// that must be replaced with sanitizer-aware versions, as well as the +// registration of weak functions with the sanitizer DLL. With this in-place, +// other sanitizer components can simply write to the .INTR and .WEAK sections. +// +//===----------------------------------------------------------------------===// + +#if defined(SANITIZER_STATIC_RUNTIME_THUNK) || \ + defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) +# include "sanitizer_win_thunk_interception.h" + +extern "C" void abort(); + +namespace __sanitizer { + +int override_function(const char *export_name, const uptr user_function) { + if (!__sanitizer_override_function(export_name, user_function)) { + abort(); + } + + return 0; +} + +int register_weak(const char *export_name, const uptr user_function) { + if (!__sanitizer_register_weak_function(export_name, user_function)) { + abort(); + } + + return 0; +} + +void initialize_thunks(const sanitizer_thunk *first, + const sanitizer_thunk *last) { + for (const sanitizer_thunk *it = first; it < last; ++it) { + if (*it) { + (*it)(); + } + } +} +} // namespace __sanitizer + +# define INTERFACE_FUNCTION(Name) +# define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name) +# include "sanitizer_common_interface.inc" + +# pragma section(".INTR$A", read) // intercept begin +# pragma section(".INTR$Z", read) // intercept end +# pragma section(".WEAK$A", read) // weak begin +# pragma section(".WEAK$Z", read) // weak end + +extern "C" { +__declspec(allocate( + ".INTR$A")) sanitizer_thunk __sanitizer_intercept_thunk_begin; +__declspec(allocate(".INTR$Z")) sanitizer_thunk __sanitizer_intercept_thunk_end; + +__declspec(allocate( + ".WEAK$A")) sanitizer_thunk __sanitizer_register_weak_thunk_begin; +__declspec(allocate( + ".WEAK$Z")) sanitizer_thunk __sanitizer_register_weak_thunk_end; +} + +extern "C" int __sanitizer_thunk_init() { + // __sanitizer_static_thunk_init is expected to be called by only one thread. + static bool flag = false; + if (flag) { + return 0; + } + flag = true; + + __sanitizer::initialize_thunks(&__sanitizer_intercept_thunk_begin, + &__sanitizer_intercept_thunk_end); + __sanitizer::initialize_thunks(&__sanitizer_register_weak_thunk_begin, + &__sanitizer_register_weak_thunk_end); + + // In DLLs, the callbacks are expected to return 0, + // otherwise CRT initialization fails. + return 0; +} + +// We want to call dll_thunk_init before C/C++ initializers / constructors are +// executed, otherwise functions like memset might be invoked. +# pragma section(".CRT$XIB", long, read) +__declspec(allocate(".CRT$XIB")) int (*__sanitizer_thunk_init_ptr)() = + __sanitizer_thunk_init; + +static void WINAPI sanitizer_thunk_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == /*DLL_PROCESS_ATTACH=*/1) + __sanitizer_thunk_init(); +} + +# pragma section(".CRT$XLAB", long, read) +__declspec(allocate(".CRT$XLAB")) void( + WINAPI *__sanitizer_thunk_thread_init_ptr)(void *, unsigned long, void *) = + sanitizer_thunk_thread_init; + +#endif // defined(SANITIZER_STATIC_RUNTIME_THUNK) || + // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) \ No newline at end of file diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h new file mode 100644 index 0000000000000..70177d68aa8e6 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h @@ -0,0 +1,81 @@ +//===-- sanitizer_win_thunk_interception.h ------------------------- -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This header provide helper macros and functions to delegate calls to the +// shared runtime that lives in the sanitizer DLL. +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_WIN_THUNK_INTERCEPTION_H +#define SANITIZER_WIN_THUNK_INTERCEPTION_H +#include + +#include "sanitizer_internal_defs.h" + +extern "C" { +__declspec(dllimport) bool __cdecl __sanitizer_override_function( + const char *export_name, __sanitizer::uptr user_function, + __sanitizer::uptr *old_function = nullptr); +__declspec(dllimport) bool __cdecl __sanitizer_override_function_by_addr( + __sanitizer::uptr source_function, __sanitizer::uptr target_function, + __sanitizer::uptr *old_target_function = nullptr); +__declspec(dllimport) bool __cdecl __sanitizer_register_weak_function( + const char *export_name, __sanitizer::uptr user_function, + __sanitizer::uptr *old_function = nullptr); +} + +using sanitizer_thunk = int (*)(); + +namespace __sanitizer { +int override_function(const char *export_name, uptr user_function); +int register_weak(const char *export_name, uptr user_function); +void initialize_thunks(const sanitizer_thunk *begin, + const sanitizer_thunk *end); +} // namespace __sanitizer + +// -------------------- Function interception macros ------------------------ // +// We can't define our own version of strlen etc. because that would lead to +// link-time or even type mismatch errors. Instead, we can declare a function +// just to be able to get its address. Me may miss the first few calls to the +// functions since it can be called before __dll_thunk_init, but that would lead +// to false negatives in the startup code before user's global initializers, +// which isn't a big deal. +// Use .INTR segment to register function pointers that are iterated over during +// startup that will replace local_function with sanitizer_export. + +#define INTERCEPT_LIBRARY_FUNCTION(local_function, sanitizer_export) \ + extern "C" void local_function(); \ + static int intercept_##local_function() { \ + return __sanitizer::override_function( \ + sanitizer_export, \ + reinterpret_cast<__sanitizer::uptr>(local_function)); \ + } \ + __pragma(section(".INTR$M", long, read)) __declspec(allocate( \ + ".INTR$M")) int (*__sanitizer_static_thunk_##local_function)() = \ + intercept_##local_function; + +// ------------------ Weak symbol registration macros ---------------------- // +// Use .WEAK segment to register function pointers that are iterated over during +// startup that will replace sanitizer_export with local_function + +#define REGISTER_WEAK_FUNCTION(local_function) \ + extern "C" void local_function(); \ + extern "C" void WEAK_EXPORT_NAME(local_function)(); \ + WIN_WEAK_IMPORT_DEF(local_function) \ + __attribute__((optnone)) static int register_weak_##local_function() { \ + if ((uintptr_t) & local_function != (uintptr_t) & \ + WEAK_EXPORT_NAME(local_function)) { \ + return __sanitizer::register_weak( \ + SANITIZER_STRINGIFY(WEAK_EXPORT_NAME(local_function)), \ + reinterpret_cast<__sanitizer::uptr>(local_function)); \ + } \ + return 0; \ + } \ + __pragma(section(".WEAK$M", long, read)) __declspec(allocate( \ + ".WEAK$M")) int (*__sanitizer_register_weak_##local_function)() = \ + register_weak_##local_function; + +#endif // SANITIZER_WIN_STATIC_RUNTIME_THUNK_H diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.cpp deleted file mode 100644 index b14bbf76d9a76..0000000000000 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===-- sanitizer_win_weak_interception.cpp -------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This module should be included in the sanitizer when it is implemented as a -// shared library on Windows (dll), in order to delegate the calls of weak -// functions to the implementation in the main executable when a strong -// definition is provided. -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_WINDOWS && SANITIZER_DYNAMIC -#include "sanitizer_win_weak_interception.h" -#include "sanitizer_allocator_interface.h" -#include "sanitizer_interface_internal.h" -#include "sanitizer_win_defs.h" -#include "interception/interception.h" - -extern "C" { -void *WINAPI GetModuleHandleA(const char *module_name); -void abort(); -} - -namespace __sanitizer { -// Try to get a pointer to real_function in the main module and override -// dll_function with that pointer. If the function isn't found, nothing changes. -int interceptWhenPossible(uptr dll_function, const char *real_function) { - uptr real = __interception::InternalGetProcAddress( - (void *)GetModuleHandleA(0), real_function); - if (real && !__interception::OverrideFunction((uptr)dll_function, real, 0)) - abort(); - return 0; -} -} // namespace __sanitizer - -// Declare weak hooks. -extern "C" { -void __sanitizer_on_print(const char *str); -void __sanitizer_weak_hook_memcmp(uptr called_pc, const void *s1, - const void *s2, uptr n, int result); -void __sanitizer_weak_hook_strcmp(uptr called_pc, const char *s1, - const char *s2, int result); -void __sanitizer_weak_hook_strncmp(uptr called_pc, const char *s1, - const char *s2, uptr n, int result); -void __sanitizer_weak_hook_strstr(uptr called_pc, const char *s1, - const char *s2, char *result); -} - -// Include Sanitizer Common interface. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "sanitizer_common_interface.inc" - -#pragma section(".WEAK$A", read) -#pragma section(".WEAK$Z", read) - -typedef void (*InterceptCB)(); -extern "C" { -__declspec(allocate(".WEAK$A")) InterceptCB __start_weak_list; -__declspec(allocate(".WEAK$Z")) InterceptCB __stop_weak_list; -} - -static int weak_intercept_init() { - static bool flag = false; - // weak_interception_init is expected to be called by only one thread. - if (flag) return 0; - flag = true; - - for (InterceptCB *it = &__start_weak_list; it < &__stop_weak_list; ++it) - if (*it) - (*it)(); - - // In DLLs, the callbacks are expected to return 0, - // otherwise CRT initialization fails. - return 0; -} - -#pragma section(".CRT$XIB", long, read) -__declspec(allocate(".CRT$XIB")) int (*__weak_intercept_preinit)() = - weak_intercept_init; - -static void WINAPI weak_intercept_thread_init(void *mod, unsigned long reason, - void *reserved) { - if (reason == /*DLL_PROCESS_ATTACH=*/1) weak_intercept_init(); -} - -#pragma section(".CRT$XLAB", long, read) -__declspec(allocate(".CRT$XLAB")) void(WINAPI *__weak_intercept_tls_init)( - void *, unsigned long, void *) = weak_intercept_thread_init; - -#endif // SANITIZER_WINDOWS && SANITIZER_DYNAMIC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h deleted file mode 100644 index 5e4d8b8def3e7..0000000000000 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- sanitizer_win_weak_interception.h ---------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This header provide helper macros to delegate calls of weak functions to the -// implementation in the main executable when a strong definition is present. -//===----------------------------------------------------------------------===// -#ifndef SANITIZER_WIN_WEAK_INTERCEPTION_H -#define SANITIZER_WIN_WEAK_INTERCEPTION_H -#include "sanitizer_internal_defs.h" - -namespace __sanitizer { -int interceptWhenPossible(uptr dll_function, const char *real_function); -} - -// ----------------- Function interception helper macros -------------------- // -// Weak functions, could be redefined in the main executable, but that is not -// necessary, so we shouldn't die if we can not find a reference. -#define INTERCEPT_WEAK(Name) interceptWhenPossible((uptr) Name, #Name); - -#define INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) \ - static int intercept_##Name() { \ - return __sanitizer::interceptWhenPossible((__sanitizer::uptr) Name, #Name);\ - } \ - __pragma(section(".WEAK$M", long, read)) \ - __declspec(allocate(".WEAK$M")) int (*__weak_intercept_##Name)() = \ - intercept_##Name; - -#endif // SANITIZER_WIN_WEAK_INTERCEPTION_H diff --git a/compiler-rt/lib/ubsan/CMakeLists.txt b/compiler-rt/lib/ubsan/CMakeLists.txt index db0b33f1276ef..5d45a53d02dbd 100644 --- a/compiler-rt/lib/ubsan/CMakeLists.txt +++ b/compiler-rt/lib/ubsan/CMakeLists.txt @@ -159,33 +159,12 @@ else() CFLAGS ${UBSAN_CXXFLAGS}) if (WIN32) - add_compiler_rt_object_libraries(UbsanWeakInterception + set(RUNTIME_THUNK_CFLAGS -DSANITIZER_DYNAMIC_RUNTIME_THUNK -DSANITIZER_STATIC_RUNTIME_THUNK) + add_compiler_rt_object_libraries(UbsanRuntimeThunk ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${UBSAN_SUPPORTED_ARCH} SOURCES - ubsan_win_weak_interception.cpp - CFLAGS ${UBSAN_CFLAGS} -DSANITIZER_DYNAMIC - DEFS ${UBSAN_COMMON_DEFINITIONS}) - - add_compiler_rt_object_libraries(UbsanDllThunk - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${UBSAN_SUPPORTED_ARCH} - SOURCES - ubsan_win_dll_thunk.cpp - CFLAGS ${UBSAN_CFLAGS} -DSANITIZER_DLL_THUNK - DEFS ${UBSAN_COMMON_DEFINITIONS}) - - set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_DYNAMIC_RUNTIME_THUNK") - if(MSVC) - list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-Zl") - elseif(CMAKE_C_COMPILER_ID MATCHES Clang) - list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-nodefaultlibs") - endif() - add_compiler_rt_object_libraries(UbsanDynamicRuntimeThunk - ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${UBSAN_SUPPORTED_ARCH} - SOURCES - ubsan_win_dynamic_runtime_thunk.cpp + ubsan_win_runtime_thunk.cpp CFLAGS ${UBSAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS} DEFS ${UBSAN_COMMON_DEFINITIONS}) endif() diff --git a/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp b/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp deleted file mode 100644 index 5ac7fc3e08e4c..0000000000000 --- a/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===-- ubsan_win_dll_thunk.cpp -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a family of thunks that should be statically linked into -// the DLLs that have instrumentation in order to delegate the calls to the -// shared runtime that lives in the main binary. -// See https://github.com/google/sanitizers/issues/209 for the details. -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DLL_THUNK -#include "sanitizer_common/sanitizer_win_dll_thunk.h" -// Ubsan interface functions. -#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "ubsan_interface.inc" -#endif // SANITIZER_DLL_THUNK diff --git a/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp b/compiler-rt/lib/ubsan/ubsan_win_runtime_thunk.cpp similarity index 62% rename from compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp rename to compiler-rt/lib/ubsan/ubsan_win_runtime_thunk.cpp index 00722b4033a53..5ca7d6f385cf2 100644 --- a/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp +++ b/compiler-rt/lib/ubsan/ubsan_win_runtime_thunk.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_win_dynamic_runtime_thunk.cpp -------------------------------===// +//===-- ubsan_win_runtime_thunk.cpp ----------------------------- --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,11 +10,14 @@ // to interact with Ubsan, when it is included in a dll. // //===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK +#if defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \ + defined(SANITIZER_STATIC_RUNTIME_THUNK) #define SANITIZER_IMPORT_INTERFACE 1 #include "sanitizer_common/sanitizer_win_defs.h" +#include "sanitizer_common/sanitizer_win_thunk_interception.h" // Define weak alias for all weak functions imported from ubsan. #define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name) +#define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name) #include "ubsan_interface.inc" -#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK +#endif // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || + // defined(SANITIZER_STATIC_RUNTIME_THUNK) diff --git a/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp b/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp deleted file mode 100644 index 01db0c0ce78ab..0000000000000 --- a/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//===-- ubsan_win_weak_interception.cpp -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// This module should be included in Ubsan when it is implemented as a shared -// library on Windows (dll), in order to delegate the calls of weak functions to -// the implementation in the main executable when a strong definition is -// provided. -//===----------------------------------------------------------------------===// -#ifdef SANITIZER_DYNAMIC -#include "sanitizer_common/sanitizer_win_weak_interception.h" -#include "ubsan_flags.h" -#include "ubsan_monitor.h" -// Check if strong definitions for weak functions are present in the main -// executable. If that is the case, override dll functions to point to strong -// implementations. -#define INTERFACE_FUNCTION(Name) -#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) -#include "ubsan_interface.inc" -#endif // SANITIZER_DYNAMIC diff --git a/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp b/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp index 2cedbc722c463..59dca32672901 100644 --- a/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp +++ b/compiler-rt/test/asan/TestCases/Darwin/interface_symbols_darwin.cpp @@ -35,6 +35,9 @@ // RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ // RUN: | grep -e "INTERFACE_\(WEAK_\)\?FUNCTION" \ // RUN: | grep -v "__sanitizer_weak_hook" \ +// RUN: | grep -v "__sanitizer_override_function" \ +// RUN: | grep -v "__sanitizer_override_function_by_addr" \ +// RUN: | grep -v "__sanitizer_register_weak_function" \ // RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports // // RUN: cat %t.imports | sort | uniq > %t.imports-sorted diff --git a/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp b/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp index ce1255c957831..2d729497548d9 100644 --- a/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/interface_symbols_linux.cpp @@ -21,6 +21,9 @@ // RUN: %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc \ // RUN: | grep -e "INTERFACE_\(WEAK_\)\?FUNCTION" \ // RUN: | grep -v "__sanitizer_weak_hook" \ +// RUN: | grep -v "__sanitizer_override_function" \ +// RUN: | grep -v "__sanitizer_override_function_by_addr" \ +// RUN: | grep -v "__sanitizer_register_weak_function" \ // RUN: | sed -e "s/.*(//" -e "s/).*//" > %t.imports // // RUN: cat %t.imports | sort | uniq > %t.imports-sorted diff --git a/compiler-rt/test/asan/TestCases/Windows/double_free.cpp b/compiler-rt/test/asan/TestCases/Windows/double_free.cpp index e288b40fac47a..71c45e7e889a2 100644 --- a/compiler-rt/test/asan/TestCases/Windows/double_free.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/double_free.cpp @@ -9,13 +9,13 @@ int main() { free(x); // CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]] // CHECK-NEXT: {{#0 .* free }} - // CHECK: {{ #[1-2] .* main .*double_free.cpp}}:[[@LINE-3]] + // CHECK: {{ #[1-3] .* main .*double_free.cpp}}:[[@LINE-3]] // CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region // CHECK-LABEL: freed by thread T0 here: // CHECK-NEXT: {{#0 .* free }} - // CHECK: {{ #[1-2] .* main .*double_free.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*double_free.cpp}}:[[@LINE-8]] // CHECK-LABEL: previously allocated by thread T0 here: // CHECK-NEXT: {{#0 .* malloc }} - // CHECK: {{ #[1-2] .* main .*double_free.cpp}}:[[@LINE-12]] + // CHECK: {{ #[1-3] .* main .*double_free.cpp}}:[[@LINE-12]] return 0; } diff --git a/compiler-rt/test/asan/TestCases/Windows/free_hook_realloc.cpp b/compiler-rt/test/asan/TestCases/Windows/free_hook_realloc.cpp index 11e8c9975cf3b..297218bf8e99f 100644 --- a/compiler-rt/test/asan/TestCases/Windows/free_hook_realloc.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/free_hook_realloc.cpp @@ -5,9 +5,6 @@ // FIXME: merge this with the common free_hook_realloc test when we can run // common tests on Windows. -// FIXME: Doesn't work with DLLs -// XFAIL: win32-dynamic-asan - #include #include #include diff --git a/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp index 7ea95d2b2184a..e5de2269ffee0 100644 --- a/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp @@ -12,6 +12,6 @@ int main() { // CHECK: [[ADDR]] is located 1 bytes before 42-byte region // CHECK: allocated by thread T0 here: // CHECK-NEXT: {{#0 .* malloc }} - // CHECK: {{ #[1-2] .* main .*malloc_left_oob.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*malloc_left_oob.cpp}}:[[@LINE-8]] free(buffer); } diff --git a/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp index 1495632456e08..6007345755d88 100644 --- a/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp @@ -12,6 +12,6 @@ int main() { // CHECK: [[ADDR]] is located 0 bytes after 42-byte region // CHECK: allocated by thread T0 here: // CHECK-NEXT: {{#0 .* malloc }} - // CHECK: {{ #[1-2] .* main .*malloc_right_oob.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*malloc_right_oob.cpp}}:[[@LINE-8]] free(buffer); } diff --git a/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp b/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp index d1eac7e55f601..59a944c75b60d 100644 --- a/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp @@ -13,8 +13,8 @@ int main() { // CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region // CHECK: freed by thread T0 here: // CHECK-NEXT: {{#0 .* free }} - // CHECK: {{ #[1-2] .* main .*malloc_uaf.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*malloc_uaf.cpp}}:[[@LINE-8]] // CHECK: previously allocated by thread T0 here: // CHECK-NEXT: {{#0 .* malloc }} - // CHECK: {{ #[1-2] .* main .*malloc_uaf.cpp}}:[[@LINE-12]] + // CHECK: {{ #[1-3] .* main .*malloc_uaf.cpp}}:[[@LINE-12]] } diff --git a/compiler-rt/test/asan/TestCases/Windows/msvc/dll_and_lib.cpp b/compiler-rt/test/asan/TestCases/Windows/msvc/dll_and_lib.cpp index 96fae6b1d6039..175bdefa7c995 100644 --- a/compiler-rt/test/asan/TestCases/Windows/msvc/dll_and_lib.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/msvc/dll_and_lib.cpp @@ -1,10 +1,9 @@ // Just make sure we can link an implib into another DLL // This used to fail between r212699 and r212814. // RUN: %clang_cl_asan -DCONFIG=1 %s -c -Fo%t.1.obj -// RUN: lld-link /nologo /DLL /OUT:%t.1.dll %t.1.obj %asan_dll_thunk +// RUN: lld-link /nologo /DLL /OUT:%t.1.dll %t.1.obj %asan_lib %asan_thunk // RUN: %clang_cl_asan -DCONFIG=2 %s -c -Fo%t.2.obj -// RUN: lld-link /nologo /DLL /OUT:%t.2.dll %t.2.obj %t.1.lib %asan_dll_thunk -// REQUIRES: asan-static-runtime +// RUN: lld-link /nologo /DLL /OUT:%t.2.dll %t.2.obj %t.1.lib %asan_lib %asan_thunk // REQUIRES: lld-available #if CONFIG==1 diff --git a/compiler-rt/test/asan/TestCases/Windows/msvc/dll_large_function.cpp b/compiler-rt/test/asan/TestCases/Windows/msvc/dll_large_function.cpp index 788488dbb8ed8..f0c3deabbcf97 100644 --- a/compiler-rt/test/asan/TestCases/Windows/msvc/dll_large_function.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/msvc/dll_large_function.cpp @@ -3,8 +3,7 @@ // from the DLL. We simulate the large function with // -mllvm -asan-instrumentation-with-call-threshold=0. // RUN: %clang_cl_asan %s -c -Fo%t.obj -mllvm -asan-instrumentation-with-call-threshold=0 -// RUN: lld-link /nologo /DLL /OUT:%t.dll %t.obj %asan_dll_thunk -// REQUIRES: asan-static-runtime +// RUN: lld-link /nologo /DLL /OUT:%t.dll %t.obj %asan_lib %asan_thunk // REQUIRES: lld-available void f(long* foo, long* bar) { diff --git a/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp index ebde5f159ae38..f1fd139c58251 100644 --- a/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp @@ -12,6 +12,6 @@ int main() { // CHECK: [[ADDR]] is located 1 bytes before 42-byte region // CHECK: allocated by thread T0 here: // CHECK-NEXT: {{#0 .* realloc }} - // CHECK: {{ #[1-2] .* main .*realloc_left_oob.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*realloc_left_oob.cpp}}:[[@LINE-8]] free(buffer); } diff --git a/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp index 281efed5d3074..ea674f53def79 100644 --- a/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp @@ -12,6 +12,6 @@ int main() { // CHECK: [[ADDR]] is located 0 bytes after 42-byte region // CHECK: allocated by thread T0 here: // CHECK-NEXT: {{#0 .* realloc }} - // CHECK: {{ #[1-2] .* main .*realloc_right_oob.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*realloc_right_oob.cpp}}:[[@LINE-8]] free(buffer); } diff --git a/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp b/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp index 6ff2217b11a25..7d9c41ef0f462 100644 --- a/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp @@ -13,8 +13,8 @@ int main() { // CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region // CHECK: freed by thread T0 here: // CHECK-NEXT: {{#0 .* free }} - // CHECK: {{ #[1-2] .* main .*realloc_uaf.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*realloc_uaf.cpp}}:[[@LINE-8]] // CHECK: previously allocated by thread T0 here: // CHECK-NEXT: {{#0 .* realloc }} - // CHECK: {{ #[1-2] .* main .*realloc_uaf.cpp}}:[[@LINE-12]] + // CHECK: {{ #[1-3] .* main .*realloc_uaf.cpp}}:[[@LINE-12]] } diff --git a/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp b/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp index be99c89e7083e..05437abc07c82 100644 --- a/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp @@ -17,6 +17,6 @@ int main() { // CHECK: [[ADDR]] is located 1 bytes before 42-byte region // CHECK: allocated by thread T0 here: // CHECK-NEXT: {{#0 .* malloc}} - // CHECK: {{ #[1-2] .* main .*symbols_path.cpp}}:[[@LINE-8]] + // CHECK: {{ #[1-3] .* main .*symbols_path.cpp}}:[[@LINE-8]] free(buffer); } diff --git a/compiler-rt/test/asan/TestCases/Windows/unsymbolized.cpp b/compiler-rt/test/asan/TestCases/Windows/unsymbolized.cpp index 0eb1e9ee91b0a..00428b809fccd 100644 --- a/compiler-rt/test/asan/TestCases/Windows/unsymbolized.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/unsymbolized.cpp @@ -4,7 +4,7 @@ // RUN: rm -f %t.pdb // RUN: %clangxx_asan -c -O2 %s -o %t.obj -// RUN: lld-link /nologo /OUT:%t.exe %t.obj %asan_lib %asan_cxx_lib +// RUN: lld-link /nologo /OUT:%t.exe %t.obj -defaultlib:libcmt -nodefaultlib:msvcrt -defaultlib:oldnames %asan_static_runtime_thunk %asan_lib // RUN: not %run %t.exe 2>&1 | FileCheck %s // REQUIRES: lld-available diff --git a/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp b/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp index 4c32c63c38fa1..35947b3253857 100644 --- a/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp @@ -15,9 +15,9 @@ int main() { // CHECK: [[ADDR]] is located 0 bytes inside of 32-byte region // CHECK: freed by thread T0 here: // CHECK-NEXT: {{#0 .* realloc }} - // CHECK: {{ #[1-2] .* main .*use_after_realloc.cpp}}:[[@LINE-9]] + // CHECK: {{ #[1-3] .* main .*use_after_realloc.cpp}}:[[@LINE-9]] // CHECK: previously allocated by thread T0 here: // CHECK-NEXT: {{#0 .* realloc }} - // CHECK: {{ #[1-2] .* main .*use_after_realloc.cpp}}:[[@LINE-14]] + // CHECK: {{ #[1-3] .* main .*use_after_realloc.cpp}}:[[@LINE-14]] free(buffer); } diff --git a/compiler-rt/test/asan/TestCases/debug_double_free.cpp b/compiler-rt/test/asan/TestCases/debug_double_free.cpp index de5ac7b0c8d5c..8a2ce40bc561f 100644 --- a/compiler-rt/test/asan/TestCases/debug_double_free.cpp +++ b/compiler-rt/test/asan/TestCases/debug_double_free.cpp @@ -4,9 +4,6 @@ #include #include -// FIXME: Doesn't work with DLLs -// XFAIL: win32-dynamic-asan - // If we use %p with MSVC, it comes out all upper case. Use %08x to get // lowercase hex. #ifdef _MSC_VER diff --git a/compiler-rt/test/asan/TestCases/debug_report.cpp b/compiler-rt/test/asan/TestCases/debug_report.cpp index 617b7ee91e18d..855642bdc0d3b 100644 --- a/compiler-rt/test/asan/TestCases/debug_report.cpp +++ b/compiler-rt/test/asan/TestCases/debug_report.cpp @@ -6,9 +6,6 @@ #include #include -// FIXME: Doesn't work with DLLs -// XFAIL: win32-dynamic-asan - int main() { // Disable stderr buffering. Needed on Windows. setvbuf(stderr, NULL, _IONBF, 0); diff --git a/compiler-rt/test/asan/TestCases/default_options.cpp b/compiler-rt/test/asan/TestCases/default_options.cpp index 526dab6450e9b..845e8a5f1793e 100644 --- a/compiler-rt/test/asan/TestCases/default_options.cpp +++ b/compiler-rt/test/asan/TestCases/default_options.cpp @@ -1,11 +1,7 @@ // RUN: %clangxx_asan -O2 %s -o %t // RUN: %run %t 2>&1 | FileCheck %s -// FIXME: Doesn't work with DLLs -// XFAIL: win32-dynamic-asan - const char *kAsanDefaultOptions = "verbosity=1 help=1"; - // Required for dyld macOS 12.0+ #if (__APPLE__) __attribute__((weak)) diff --git a/compiler-rt/test/asan/TestCases/on_error_callback.cpp b/compiler-rt/test/asan/TestCases/on_error_callback.cpp index f65a8f1abe831..c38a36f0e33bd 100644 --- a/compiler-rt/test/asan/TestCases/on_error_callback.cpp +++ b/compiler-rt/test/asan/TestCases/on_error_callback.cpp @@ -1,8 +1,5 @@ // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s -// FIXME: Doesn't work with DLLs -// XFAIL: win32-dynamic-asan - #include #include diff --git a/compiler-rt/test/asan/TestCases/report_error_summary.cpp b/compiler-rt/test/asan/TestCases/report_error_summary.cpp index d565d2add7793..9e024e35bed86 100644 --- a/compiler-rt/test/asan/TestCases/report_error_summary.cpp +++ b/compiler-rt/test/asan/TestCases/report_error_summary.cpp @@ -1,8 +1,5 @@ // RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s -// FIXME: Doesn't work with DLLs -// XFAIL: win32-dynamic-asan - #include // Required for ld64 macOS 12.0+ diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py index 83b3cbe789cac..05ed7e8dd294e 100644 --- a/compiler-rt/test/asan/lit.cfg.py +++ b/compiler-rt/test/asan/lit.cfg.py @@ -130,6 +130,11 @@ def build_invocation(compile_flags, with_lto=False): config.compiler_rt_libdir, "libclang_rt.asan_{}_dynamic.dylib".format(config.apple_platform), ) + elif config.host_os == "Windows": + shared_libasan_path = os.path.join( + config.compiler_rt_libdir, + "clang_rt.asan_dynamic-{}.lib".format(config.target_suffix), + ) else: lit_config.warning( "%shared_libasan substitution not set but dynamic ASan is available." @@ -178,8 +183,22 @@ def build_invocation(compile_flags, with_lto=False): base_lib = os.path.join( config.compiler_rt_libdir, "clang_rt.asan%%s%s.lib" % config.target_suffix ) - config.substitutions.append(("%asan_lib", base_lib % "")) + config.substitutions.append(("%asan_lib", base_lib % "_dynamic")) + if config.asan_dynamic: + config.substitutions.append( + ("%asan_thunk", base_lib % "_dynamic_runtime_thunk") + ) + else: + config.substitutions.append( + ("%asan_thunk", base_lib % "_static_runtime_thunk") + ) config.substitutions.append(("%asan_cxx_lib", base_lib % "_cxx")) + config.substitutions.append( + ("%asan_dynamic_runtime_thunk", base_lib % "_dynamic_runtime_thunk") + ) + config.substitutions.append( + ("%asan_static_runtime_thunk", base_lib % "_static_runtime_thunk") + ) config.substitutions.append(("%asan_dll_thunk", base_lib % "_dll_thunk")) else: # To make some of these tests work on MinGW target without changing their @@ -262,7 +281,7 @@ def build_invocation(compile_flags, with_lto=False): # Add the RT libdir to PATH directly so that we can successfully run the gtest # binary to list its tests. -if config.host_os == "Windows" and config.asan_dynamic: +if config.host_os == "Windows": os.environ["PATH"] = os.path.pathsep.join( [config.compiler_rt_libdir, os.environ.get("PATH", "")] )