[clang] [compiler-rt] [asan][windows] Eliminate the static asan runtime on windows (PR #81677)

via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 13 14:18:37 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Charlie Barto (barcharcraz)

<details>
<summary>Changes</summary>

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

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

1. Build one DLL that includes everything debug mode needs (not included here, already contributed upstream).
* Remove #if _DEBUG checks everywhere.
* In some places, this needed to be replaced with a runtime check. In asan_win.cpp, IsDebugRuntimePresent was added where we are searching for allocations prior to ASAN initialization.
* In asan_win_runtime_functions.cpp and interception_win.cpp, we need to be aware of debug runtime DLLs even when not built with _DEBUG.
2. Redirect statically linked functions to the ASAN DLL for /MT
* New exports for each of the C allocation APIs so that the statically linked portion of the runtime can call them (see asan_malloc_win.cpp, search MALLOC_DLL_EXPORT). Since we want our stack trace information to be accurate and without noise, this means we need to capture stack frame info from the original call and tell it to our DLL export. For this, I have reused the __asan_win_new_delete_data used for op new/delete support from asan_win_new_delete_thunk_common.h and moved it into asan_win_thunk_common.h renamed as __asan_win_stack_data.
* For the C allocation APIs, a new file is included in the statically-linked /WHOLEARCHIVE lib - asan_malloc_win_thunk.cpp. These functions simply provide definitions for malloc/free/etc to be used instead of the UCRT's definitions for /MT and instead call the ASAN DLL export. /INFERASANLIBS ensures libucrt.lib will not take precedence via /WHOLEARCHIVE.
* For other APIs, the interception code was called, so a new export is provided: __sanitizer_override_function. __sanitizer_override_function_by_addr is also provided to support __except_handler4 on x86 (due to the security cookie being per-module).
3. Support weak symbols for /MD
* We have customers (CoreCLR) that rely on this behavior and would force /MT to get it.
* There was sanitizer_win_weak_interception.cpp before, which did some stuff for setting up the .WEAK section, but this only worked on /MT. Now stuff registered in the .WEAK section is passed to the ASAN DLL via new export __sanitizer_register_weak_function (impl in sanitizer_win_interception.cpp). Unlike linux, multiple weak symbol registrations are possible here. Current behavior is to give priority on module load order such that whoever loads last (so priority is given to the EXE) will have their weak symbol registered.
* Unfortunately, the registration can only occur during the user module startup, which is after ASAN DLL startup, so any weak symbols used by ASAN during initialization will not be picked up. This is most notable for __asan_default_options and friends (see asan_flags.cpp). A mechanism was made to add a callback for when a certain weak symbol was registered, so now we process __asan_default_options during module startup instead of ASAN startup. This is a change in behavior, but there's no real way around this due to how DLLs are.
4. Build reorganization
* I noticed that our current build configuration is very MSVC-specific and so did a bit of reworking. Removed a lot of create_multiple_windows_obj_lib use since it's no longer needed and it changed how we needed to refer to each object_lib by adding runtime configuration to the name, conflicting with how it works for non-MSVC.
* No more Win32 static build, use /MD everywhere.
* Building with /Zl to avoid defaultlib warnings.

In addition:
* I've reapplied "[sanitizer][asan][win] Intercept _strdup on Windows instead of strdup" which broke the previous static asan runtime. That runtime is gone now and this change is required for the strdup tests to work.
* I've added windows paths to the filtering for internal stack frames, which helps some tests pass.
* I've modified the MSVC clang driver to support linking the correct asan libraries, including via defining _DLL (which triggers different defaultlibs and should result in the asan dll thunk being linked, along with the dll CRT (via defaultlib directives).
* I've made passing -static-libsan an error on windows, and made -shared-libsan the default. I'm not sure I did this correctly, or in the best way.
* started interception strtoll for the static runtime. This is a bug that I uncovered on our side while preparing this PR, we have the relevant test disabled so we didn't catch it.
* Modified the test harnesses to add substitutions for the dynamic and static thunks and to make the library substitutions point to the dynamic asan runtime for all test configurations on windows. Both the static and dynamic windows test configurations remain, because they correspond to the static and dynamic CRT, not the static and dynamic asan runtime library.

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

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


---

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


71 Files Affected:

- (modified) clang/lib/Driver/SanitizerArgs.cpp (+10-4) 
- (modified) clang/lib/Driver/ToolChains/MSVC.cpp (+11-15) 
- (modified) compiler-rt/CMakeLists.txt (+6-2) 
- (modified) compiler-rt/lib/asan/CMakeLists.txt (+85-77) 
- (modified) compiler-rt/lib/asan/asan_flags.cpp (+85-11) 
- (modified) compiler-rt/lib/asan/asan_globals_win.cpp (+3-1) 
- (modified) compiler-rt/lib/asan/asan_interceptors.cpp (+17-2) 
- (modified) compiler-rt/lib/asan/asan_malloc_win.cpp (+42-55) 
- (added) compiler-rt/lib/asan/asan_malloc_win_thunk.cpp (+229) 
- (added) compiler-rt/lib/asan/asan_win_common_runtime_thunk.cpp (+112) 
- (added) compiler-rt/lib/asan/asan_win_common_runtime_thunk.h (+38) 
- (removed) compiler-rt/lib/asan/asan_win_dll_thunk.cpp (-165) 
- (modified) compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cpp (+14-90) 
- (added) compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp (+110) 
- (modified) compiler-rt/lib/interception/interception_win.cpp (+10-1) 
- (modified) compiler-rt/lib/profile/CMakeLists.txt (+6) 
- (modified) compiler-rt/lib/sanitizer_common/CMakeLists.txt (+13-43) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc (+6) 
- (renamed) compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp (+12-9) 
- (removed) compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp (-23) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp (+4) 
- (removed) compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h (-181) 
- (added) compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h (+72) 
- (added) compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp (+154) 
- (added) compiler-rt/lib/sanitizer_common/sanitizer_win_interception.h (+32) 
- (renamed) compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp (+7-7) 
- (added) compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.cpp (+110) 
- (added) compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h (+81) 
- (removed) compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.cpp (-94) 
- (removed) compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h (-32) 
- (modified) compiler-rt/lib/ubsan/CMakeLists.txt (+4-24) 
- (removed) compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp (-20) 
- (renamed) compiler-rt/lib/ubsan/ubsan_win_runtime_thunk.cpp (+7-4) 
- (removed) compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp (-23) 
- (modified) compiler-rt/test/asan/TestCases/Windows/bitfield_uaf.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/calloc_left_oob.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/calloc_right_oob.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/calloc_uaf.cpp (+10-10) 
- (added) compiler-rt/test/asan/TestCases/Windows/defaultlibs_check.cpp (+8) 
- (modified) compiler-rt/test/asan/TestCases/Windows/dll_heap_allocation.cpp (+1-1) 
- (modified) compiler-rt/test/asan/TestCases/Windows/dll_host.cpp (-42) 
- (modified) compiler-rt/test/asan/TestCases/Windows/dll_malloc_left_oob.cpp (+11-11) 
- (modified) compiler-rt/test/asan/TestCases/Windows/dll_malloc_uaf.cpp (+15-15) 
- (modified) compiler-rt/test/asan/TestCases/Windows/double_free.cpp (+10-10) 
- (modified) compiler-rt/test/asan/TestCases/Windows/free_hook_realloc.cpp (-3) 
- (modified) compiler-rt/test/asan/TestCases/Windows/intercept_strdup.cpp (+13-13) 
- (removed) compiler-rt/test/asan/TestCases/Windows/interface_symbols_windows.cpp (-56) 
- (modified) compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp (+10-10) 
- (modified) compiler-rt/test/asan/TestCases/Windows/msvc/dll_and_lib.cpp (+2-3) 
- (modified) compiler-rt/test/asan/TestCases/Windows/msvc/dll_large_function.cpp (+1-2) 
- (modified) compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp (+10-10) 
- (modified) compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp (+7-7) 
- (modified) compiler-rt/test/asan/TestCases/Windows/unsymbolized.cpp (+1-1) 
- (modified) compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp (+10-10) 
- (modified) compiler-rt/test/asan/TestCases/calloc-overflow.cpp (+1-1) 
- (modified) compiler-rt/test/asan/TestCases/debug_double_free.cpp (-3) 
- (modified) compiler-rt/test/asan/TestCases/debug_report.cpp (-3) 
- (modified) compiler-rt/test/asan/TestCases/deep_stack_uaf.cpp (+1-1) 
- (modified) compiler-rt/test/asan/TestCases/default_options.cpp (-4) 
- (modified) compiler-rt/test/asan/TestCases/double-free.cpp (+2-2) 
- (modified) compiler-rt/test/asan/TestCases/malloc-size-too-big.cpp (+1-1) 
- (modified) compiler-rt/test/asan/TestCases/on_error_callback.cpp (-3) 
- (modified) compiler-rt/test/asan/TestCases/report_error_summary.cpp (-3) 
- (modified) compiler-rt/test/asan/TestCases/strncpy-overflow.cpp (+1-1) 
- (modified) compiler-rt/test/asan/TestCases/use-after-free-right.cpp (+2-2) 
- (modified) compiler-rt/test/asan/TestCases/use-after-free.cpp (+2-2) 
- (modified) compiler-rt/test/asan/lit.cfg.py (+12-1) 


``````````diff
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 56d497eb4c32b8..c631e5d828ccfd 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -900,10 +900,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 396522225158de..3812246da1d25e 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -196,10 +196,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(
@@ -208,19 +208,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/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt
index bbb4e8d7c333e4..ed0a13c10be962 100644
--- a/compiler-rt/CMakeLists.txt
+++ b/compiler-rt/CMakeLists.txt
@@ -375,8 +375,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 f83ae82d42935a..bd973479fe9724 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
@@ -85,6 +99,9 @@ SET(ASAN_HEADERS
 include_directories(..)
 
 set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+
+append_list_if(MSVC /Zl ASAN_CFLAGS)
+
 set(ASAN_COMMON_DEFINITIONS ${COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION})
 
 append_rtti_flag(OFF ASAN_CFLAGS)
@@ -133,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})
@@ -218,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)
@@ -275,25 +298,11 @@ else()
     endif()
 
     set(ASAN_DYNAMIC_WEAK_INTERCEPTION)
-    if (WIN32)
-      add_compiler_rt_object_libraries(AsanWeakInterception
-        ${SANITIZER_COMMON_SUPPORTED_OS}
-        ARCHS ${arch}
-        SOURCES
-          asan_win_weak_interception.cpp
-        CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DYNAMIC
-        DEFS ${ASAN_COMMON_DEFINITIONS})
-      set(ASAN_DYNAMIC_WEAK_INTERCEPTION
-          AsanWeakInterception
-          UbsanWeakInterception
-          SancovWeakInterception
-          SanitizerCommonWeakInterception)
-    endif()
-
     add_compiler_rt_runtime(clang_rt.asan
       SHARED
       ARCHS ${arch}
       OBJECT_LIBS ${ASAN_COMMON_RUNTIME_OBJECT_LIBS}
+              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.
@@ -321,36 +330,12 @@ else()
     endif()
 
     if (WIN32)
-      add_compiler_rt_object_libraries(AsanDllThunk
-        ${SANITIZER_COMMON_SUPPORTED_OS}
-        ARCHS ${arch}
-        SOURCES asan_globals_win.cpp
-                asan_win_dll_thunk.cpp
-        CFLAGS ${ASAN_CFLAGS} -DSANITIZER_DLL_THUNK
-        DEFS ${ASAN_COMMON_DEFINITIONS})
-
-      add_compiler_rt_runtime(clang_rt.asan_dll_thunk
-        STATIC
-        ARCHS ${arch}
-        OBJECT_LIBS AsanDllThunk
-                    UbsanDllThunk
-                    SancovDllThunk
-                    SanitizerCommonDllThunk
-        SOURCES $<TARGET_OBJECTS:RTInterception.${arch}>
-        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})
 
@@ -358,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 23989843323211..56deb1b0d082b8 100644
--- a/compiler-rt/lib/asan/asan_flags.cpp
+++ b/compiler-rt/lib/asan/asan_flags.cpp
@@ -11,14 +11,16 @@
 // ASan flag parsing logic.
 //===----------------------------------------------------------------------===//
 
-#include "asan_activation.h"
 #include "asan_flags.h"
+
+#include "asan_activation.h"
 #include "asan_interface_internal.h"
 #include "asan_stack.h"
 #include "lsan/lsan_common.h"
 #include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_win_interception.h"
 #include "ubsan/ubsan_flags.h"
 #include "ubsan/ubsan_platform.h"
 
@@ -47,7 +49,21 @@ static void RegisterAsanFlags(FlagParser *parser, Flags *f) {
 #undef ASAN_FLAG
 }
 
-void InitializeFlags() {
+static void DisplayHelpMessages(FlagParser *parser) {
+  // TODO(eugenis): dump all flags at verbosity>=2?
+  if (Verbosity()) {
+    ReportUnrecognizedFlags();
+  }
+
+  if (common_flags()->help) {
+    parser->PrintFlagDescriptions();
+  }
+}
+
+static void InitializeDefaultFlags() {
+  Flags *f = flags();
+  FlagParser asan_parser;
+
   // Set the default values and prepare for parsing ASan and common flags.
   SetCommonFlagsDefaults();
   {
@@ -60,10 +76,8 @@ void InitializeFlags() {
     cf.exitcode = 1;
     OverrideCommonFlags(cf);
   }
-  Flags *f = flags();
   f->SetDefaults();
 
-  FlagParser asan_parser;
   RegisterAsanFlags(&asan_parser, f);
   RegisterCommonFlags(&asan_parser);
 
@@ -126,13 +140,12 @@ void InitializeFlags() {
 
   InitializeCommonFlags();
 
-  // TODO(eugenis): dump all flags at verbosity>=2?
-  if (Verbosity()) ReportUnrecognizedFlags();
+  // TODO(samsonov): print all of the flags (ASan, LSan, common).
+  DisplayHelpMessages(&asan_parser);
+}
 
-  if (common_flags()->help) {
-    // TODO(samsonov): print all of the flags (ASan, LSan, common).
-    asan_parser.PrintFlagDescriptions();
-  }
+static void ProcessFlags() {
+  Flags *f = flags();
 
   // Flag validation:
   if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) {
@@ -199,6 +212,67 @@ void InitializeFlags() {
   }
 }
 
+void InitializeFlags() {
+  InitializeDefaultFlags();
+  ProcessFlags();
+
+#if SANITIZER_WINDOWS
+  // On Windows, weak symbols are emulated by having the user program
+  // register which weak functions are defined.
+  // The ASAN DLL will initialize flags prior to user module initialization,
+  // so __asan_default_options will not point to the user definition yet.
+  // We still want to ensure we capture when options are passed via
+  // __asan_default_options, so we add a callback to be run
+  // when it is registered with the runtime.
+
+  // There is theoretically time between the initial ProcessFlags and
+  // registering the weak callback where a weak function could be added and we
+  // would miss it, but in practice, InitializeFlags will always happen under
+  // the loader lock (if built as a DLL) and so will any calls to
+  // __sanitizer_register_weak_function.
+  AddRegisterWeakFunctionCallback(
+      reinterpret_cast<uptr>(__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<uptr>(__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<uptr>(__lsan_default_options), []() {
+        FlagParser lsan_parser;
+
+        __lsan::RegisterLsanFlags(&lsan_parser, __lsan::flags());
+        RegisterCommonFlags(&lsan_parser);
+        lsan_parser.ParseString(__lsan_default_options());
+
+        // To match normal behavior, do not print LSan help.
+        ProcessFlags();
+      });
+#  endif
+
+#endif
+}
+
 }  // namespace __asan
 
 SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) {
diff --git a/compiler-rt/lib/asan/asan_globals_win.cpp b/compiler-rt/lib/asan/asan_globals_win.cpp
index 19af88ab12b40a..8267f07b9cce49 100644
--- a/compiler-rt/lib/asan/asan_globals_win.cpp
+++ b/compiler-rt/lib/asan/asan_globals_win.cpp
@@ -28,7 +28,9 @@ static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
   __asan_global *end = &__asan_globals_end;
   uptr bytediff = (uptr)end - (uptr)start;
   if (bytediff % sizeof(__asan_global) != 0) {
-#if defined(SANITIZER_DLL_THUNK) || defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
+#  if defined(SANITIZER_DLL_THUNK) ||             \
+      defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \
+      defined(SANITIZER_STATIC_RUNTIME_THUNK)
     __debugbreak();
 #else
     CHECK("corrupt asan global array");
diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index 4de2fa356374a6..1ca54d404bcaa3 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -558,6 +558,17 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) {
   return REAL(strcpy)(to, from);
 }
 
+// Windows doesn't always define the strdup identifier,
+// and when it does it's a macro defined to either _strdup
+// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so
+// we want to intercept that. push/pop_macro are used to avoid problems
+// if this file ends up including <string.h> in the future.
+#  if SANITIZER_WINDOWS
+#    pragma push_macro("strdup")
+#    undef strdup
+#    define strdup _strdup
+#  endif
+
 INTERCEPTOR(char*, strdup, const char *s) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, strdup);
@@ -575,7 +586,7 @@ INTERCEPTOR(char*, strdup, const char *s) {
   return reinterpret_cast<char*>(new_mem);
 }
 
-#if ASAN_INTERCEPT___STRDUP
+#  if ASAN_INTERCEPT___STRDUP
 INTERCEPTOR(char*, __strdup, const char *s) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, strdup);
@@ -758,7 +769,7 @@ void InitializeAsanInterceptors() {
   ASAN_INTERCEPT_FUNC(strncat);
   ASAN_INTERCEPT_FUNC(strncpy);
   ASAN_INTERCEPT_FUNC(strdup);
-#if ASAN_INTERCEPT___STRDUP
+#  if ASAN_INTERCEPT___STRDUP
   ASAN_INTERCEPT_FUNC(__strdup);
 #endif
 #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
@@ -849,6 +860,10 @@ void InitializeAsanInterceptors() {
   VReport(1, "AddressSanitizer: libc interceptors initialized\n");
 }
 
+#  if SANITIZER_WINDOWS
+#    pragma pop_macro("strdup")
+#  endif
+
 } // namespace __asan
 
 #endif  // !SANITIZER_FUCHSIA
diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp
index 7e1d04c36dd580..3278f072198769 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -58,97 +58,69 @@ using namespace __asan;
 // MD: Memory allocation functions are defined in the CRT .dll,
 // so we have to intercept them before they are called for the first time.
 
-#if ASAN_DYNAMIC
-# define ALLOCATION_FUNCTION_ATTRIBUTE
-#else
-# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-#endif
-
 extern "C" {
-ALLOCATION_FUNCTION_ATTRIBUTE
-size_t _msize(void *ptr) {
+__declspec(noinline) size_t _msize(void *ptr) {
   GET_CURRENT_PC_BP_SP;
   (void)sp;
   return asan_malloc_usable_size(ptr, pc, bp);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-size_t _msize_base(void *ptr) {
-  return _msize...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/81677


More information about the cfe-commits mailing list