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

Charlie Barto via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 16 13:36:24 PST 2024


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

>From f20091e08a1fd149cf781bc43909a73f4e877d2a Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Tue, 6 Feb 2024 17:16:03 -0800
Subject: [PATCH 01/15] report symbols in clang_rt. or \compiler-rt\lib\ as
 internal.

This is the windows equivalent to the existing filters.
---
 .../lib/sanitizer_common/sanitizer_symbolizer_report.cpp      | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
index f6b157c07c6557..ffbaf1468ec8ff 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -39,8 +39,12 @@ static bool FrameIsInternal(const SymbolizedStack *frame) {
                internal_strstr(file, "/include/c++/") ||
                internal_strstr(file, "/include/g++")))
     return true;
+  if (file && internal_strstr(file, "\\compiler-rt\\lib\\"))
+    return true;
   if (module && (internal_strstr(module, "libclang_rt.")))
     return true;
+  if (module && (internal_strstr(module, "clang_rt.")))
+    return true;
   return false;
 }
 

>From f4c86742805dedeceb2871505b42370d137f17e2 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Wed, 7 Feb 2024 09:36:06 -0800
Subject: [PATCH 02/15] Reapply "[sanitizer][asan][win] Intercept _strdup on
 Windows instead of strdup"

This reverts commit 03dc87e93937bf25a48bc77d0006c59f37b1855d.
---
 compiler-rt/lib/asan/asan_interceptors.cpp | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

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

>From ad671de2a00a5406f3e2e46ab7550d8248b86a56 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 17:53:16 -0800
Subject: [PATCH 03/15] Build ASAN libraries with /MD instead of /MT on winodws

The profiling runtime is still built with /MT, as it does not work with
/MD (and not well supported on windows)
---
 compiler-rt/CMakeLists.txt             | 8 ++++++--
 compiler-rt/lib/profile/CMakeLists.txt | 6 ++++++
 2 files changed, 12 insertions(+), 2 deletions(-)

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/profile/CMakeLists.txt b/compiler-rt/lib/profile/CMakeLists.txt
index 45e51648917515..ef23492514898b 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.

>From 8830c8a483ad61a883fc4e0894cfa413100e7896 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 17:55:10 -0800
Subject: [PATCH 04/15] When compiling with clang-cl or MSVC pass /Zl (that's a
 little L)

/Zl is the equivalent of -nodefaultlibs.
---
 compiler-rt/lib/asan/CMakeLists.txt             | 3 +++
 compiler-rt/lib/sanitizer_common/CMakeLists.txt | 2 ++
 compiler-rt/lib/ubsan/CMakeLists.txt            | 1 +
 3 files changed, 6 insertions(+)

diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt
index f83ae82d42935a..601750f72175d6 100644
--- a/compiler-rt/lib/asan/CMakeLists.txt
+++ b/compiler-rt/lib/asan/CMakeLists.txt
@@ -85,6 +85,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)
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index f762524c333acf..f2b4ac72ae1573 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -218,6 +218,8 @@ include_directories(..)
 set(SANITIZER_COMMON_DEFINITIONS
   HAVE_RPC_XDR_H=${HAVE_RPC_XDR_H})
 
+# note: L not I, this is nodefaultlibs for msvc
+append_list_if(MSVC /Zl SANITIZER_COMMON_CFLAGS)
 set(SANITIZER_CFLAGS ${SANITIZER_COMMON_CFLAGS})
 
 # Too many existing bugs, needs cleanup.
diff --git a/compiler-rt/lib/ubsan/CMakeLists.txt b/compiler-rt/lib/ubsan/CMakeLists.txt
index 3f1e12ed9ac66f..db0b33f1276ef2 100644
--- a/compiler-rt/lib/ubsan/CMakeLists.txt
+++ b/compiler-rt/lib/ubsan/CMakeLists.txt
@@ -41,6 +41,7 @@ set(UBSAN_HEADERS
 include_directories(..)
 
 set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_list_if(MSVC /Zl UBSAN_CFLAGS)
 append_rtti_flag(OFF UBSAN_CFLAGS)
 append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CFLAGS)
 

>From 99681f51093afe4d10229265c8181b2f4cc5df06 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:27:23 -0800
Subject: [PATCH 05/15] Remove the static ASAN runtimes

Instead build only ONE asan runtime on windows.

File Overview:

* asan_malloc_win_thunk.cpp
	Contains interceptors for malloc/free for applications using the static CRT.
	These are intercepted with an oldnames style library that takes precedence
	over the CRT because of linker search order. This is used instead of
	the library interception routines used for other functions so that we
	can intercept mallocs that happen before our interceptors run. Some
	other CRT functions are also included here, because they are provided by the same
	objects as allocation functions in the debug CRT.
* asan_win_common_runtime_thunk.cpp
	just the common init code for both static and dynamic CRTs
* asan_win_static_runtime_thunk.cpp
	static CRT specific initialization
* asan_win_dynamic_runtime_thunk.cpp
	dynamic crt initialization, most of the content that was here
	has been moved to the common runtime thunk
* asan_win_dll_thunk.cpp
	This used to provide functionality to redirect
	calls from DLLs to asan instrumented functions in the main library,
	but this never worked that well and was a nightmare. It's gone now
* sanitizer_common/sanitizer_common_interface.inc:
	The added functions are for the thunks to be able to delegate to the
	asan runtime DLL in order to override functions that live in the application
	executable at initialization. The ASAN dll can't do this itself because it
	doesn't have a way to get the addresses of these functions.
* sanitizer_common/sanitizer_win_immortalize:
	This is just an implementation of call_once that doens't require the CRT
	or C++ stdlib. We need this because we need to do this sort of thing
	before the CRT has initialized. This infrastructure is kinda ugly, we're sorry.
* sanitizer_common/sanitizer_win_interception.cpp:
	Provides the interface inside the sanitizer runtime DLL that instramented apps
	call to intercept stuff.
* sanitizer_common/sanitizer_win_thunk_interception.cpp:
	this is the code to setup and run the static initializers and/or TLS
	initializers, implemented basically how any initializers are on windows,
	these ones are registered before all the CRT initializers.
* sanitizer_common/sanitizer_win_thunk_interception.h
	INTERCEPT_LIBRARY_FUNCTION and REGISTER_WEAK_FUNCTION
	are the called initializers for each relevant function inside the instrumented
	binary. Note the optimizer is disabled for weak function registration routines
	because it detects that the two functions being compared have different names
	and deduces they must be the same, and no actual codegen for the if is required,
	causing an infinite loop. Clang does this in debug mode as well as release mode,
	and the cast to uintptr_t is required to suppress it in debug mode.
*
---
 compiler-rt/lib/asan/CMakeLists.txt           | 159 ++++++------
 compiler-rt/lib/asan/asan_globals_win.cpp     |   4 +-
 .../lib/asan/asan_malloc_win_thunk.cpp        | 229 ++++++++++++++++++
 .../asan/asan_win_common_runtime_thunk.cpp    | 112 +++++++++
 .../lib/asan/asan_win_common_runtime_thunk.h  |  38 +++
 compiler-rt/lib/asan/asan_win_dll_thunk.cpp   | 165 -------------
 .../asan/asan_win_dynamic_runtime_thunk.cpp   | 104 ++------
 .../asan/asan_win_static_runtime_thunk.cpp    | 109 +++++++++
 .../lib/sanitizer_common/CMakeLists.txt       |  54 +----
 .../sanitizer_common_interface.inc            |   6 +
 ... sanitizer_coverage_win_runtime_thunk.cpp} |  21 +-
 ...nitizer_coverage_win_weak_interception.cpp |  23 --
 .../sanitizer_win_dll_thunk.h                 | 181 --------------
 .../sanitizer_win_immortalize.h               |  72 ++++++
 .../sanitizer_win_interception.cpp            | 154 ++++++++++++
 .../sanitizer_win_interception.h              |  32 +++
 ...nk.cpp => sanitizer_win_runtime_thunk.cpp} |  14 +-
 .../sanitizer_win_thunk_interception.cpp      | 110 +++++++++
 .../sanitizer_win_thunk_interception.h        |  81 +++++++
 .../sanitizer_win_weak_interception.cpp       |  94 -------
 .../sanitizer_win_weak_interception.h         |  32 ---
 compiler-rt/lib/ubsan/CMakeLists.txt          |  27 +--
 compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp |  20 --
 ..._thunk.cpp => ubsan_win_runtime_thunk.cpp} |  11 +-
 .../lib/ubsan/ubsan_win_weak_interception.cpp |  23 --
 25 files changed, 1082 insertions(+), 793 deletions(-)
 create mode 100644 compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
 create mode 100644 compiler-rt/lib/asan/asan_win_common_runtime_thunk.cpp
 create mode 100644 compiler-rt/lib/asan/asan_win_common_runtime_thunk.h
 delete mode 100644 compiler-rt/lib/asan/asan_win_dll_thunk.cpp
 create mode 100644 compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
 rename compiler-rt/lib/sanitizer_common/{sanitizer_coverage_win_dynamic_runtime_thunk.cpp => sanitizer_coverage_win_runtime_thunk.cpp} (59%)
 delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp
 delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_interception.h
 rename compiler-rt/lib/sanitizer_common/{sanitizer_win_dynamic_runtime_thunk.cpp => sanitizer_win_runtime_thunk.cpp} (76%)
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.cpp
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
 delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.cpp
 delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_weak_interception.h
 delete mode 100644 compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp
 rename compiler-rt/lib/ubsan/{ubsan_win_dynamic_runtime_thunk.cpp => ubsan_win_runtime_thunk.cpp} (62%)
 delete mode 100644 compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp

diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt
index 601750f72175d6..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
@@ -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 $<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})
 
@@ -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_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_malloc_win_thunk.cpp b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
new file mode 100644
index 00000000000000..abf515b77c4a9f
--- /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 00000000000000..d2c9e66c313379
--- /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 <windows.h>
+
+#  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 00000000000000..66285eb31ae994
--- /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 0fa636bec0d001..00000000000000
--- 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 f0b5ec9eef7f99..421fe651b7d919 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 <windows.h>
-
-// 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 <windows.h>
 
-// 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 00000000000000..3aa90421962be4
--- /dev/null
+++ b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
@@ -0,0 +1,109 @@
+//===-- 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(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/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index f2b4ac72ae1573..9e529ff8ec3ddd 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
@@ -210,7 +211,8 @@ set(SANITIZER_IMPL_HEADERS
   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(..)
@@ -304,57 +306,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 557207fe62ac6d..11f1d963bd6f43 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_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 0bdf0c5aed418d..281944643f216f 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 55263981705fa6..00000000000000
--- 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.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.h
deleted file mode 100644
index 639d91a2edaec4..00000000000000
--- 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_immortalize.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h
new file mode 100644
index 00000000000000..43f0675fe86eeb
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h
@@ -0,0 +1,72 @@
+//===-- 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 <class Ty>
+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 <class Ty, typename Arg>
+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 <class Ty>
+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<Ty>, &storage, nullptr);
+  return reinterpret_cast<Ty&>(storage);
+}
+
+template <class Ty, typename Arg>
+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<Ty, Arg>, &storage, &arg);
+  return reinterpret_cast<Ty&>(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 00000000000000..a88ca413b6132f
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp
@@ -0,0 +1,154 @@
+//===-- 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 <stddef.h>
+
+#  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<WeakCallbackList *, 11>;
+
+static WeakCallbackMap *GetWeakCallbackMap() {
+  return &immortalize<WeakCallbackMap>();
+}
+
+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 00000000000000..70ae3d6bf31f2a
--- /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_dynamic_runtime_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp
similarity index 76%
rename from compiler-rt/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp
rename to compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp
index 87c032c6e61bc9..ab2aa594c087bf 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp
@@ -11,16 +11,16 @@
 //
 //===----------------------------------------------------------------------===//
 #ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
-#define SANITIZER_IMPORT_INTERFACE 1
-#include "sanitizer_win_defs.h"
+#  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
+#  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() {}
-}
+}  // namespace __sanitizer
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 00000000000000..edf764f7ace6bb
--- /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 00000000000000..2cdadddfa2f69a
--- /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_STATIC_RUNTIME_THUNK_H
+#define SANITIZER_WIN_STATIC_RUNTIME_THUNK_H
+#include <stdint.h>
+
+#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 b14bbf76d9a765..00000000000000
--- 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 5e4d8b8def3e7d..00000000000000
--- 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 db0b33f1276ef2..5d45a53d02dbd3 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 5ac7fc3e08e4c7..00000000000000
--- 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 00722b4033a53f..5ca7d6f385cf27 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 01db0c0ce78abe..00000000000000
--- 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

>From f99a63e5d5055ad6db152d34c05f1529ddb70f9e Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:28:46 -0800
Subject: [PATCH 06/15] make it an error to pass -static-libsan on windows and
 make shared the default.

---
 clang/lib/Driver/SanitizerArgs.cpp | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

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();
 

>From 7b189a6178e70d57a09afe43e070bb52bb7421d2 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:34:18 -0800
Subject: [PATCH 07/15] Teach the MSVC toolchain driver to link the correct
 asan libraries.

Now that the static runtime is gone the required librares are different.

Note that /MD or -D_DLL causes the dynamic runtime to get linked,
this is a little gross but emulates the behavior of MSVC.

"Real" msvc will link the debug build of asan if you specify /DEBUG or _DEBUG,
but that's not really necessary and requires building multiple
configurations from the same tree.
---
 clang/lib/Driver/ToolChains/MSVC.cpp | 26 +++++++++++---------------
 1 file changed, 11 insertions(+), 15 deletions(-)

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")));
     }
   }
 

>From ae456a25c556be3355c63fc90c97f93128f1deeb Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:37:50 -0800
Subject: [PATCH 08/15] Because all DLLs get initialized before the main module

weak functions are registered after the asan runtime initializes.

This means __asan_default_options isn't available during asan
runtime initialization. Thus we split asan flag processing into
two parts and register a callback for the second part that's
executed after __asan_default_options is registered.
---
 compiler-rt/lib/asan/asan_flags.cpp | 96 +++++++++++++++++++++++++----
 1 file changed, 85 insertions(+), 11 deletions(-)

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) {

>From 31c8dca6ef393dd7ae5729688b56204c8fc065d2 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:41:10 -0800
Subject: [PATCH 09/15] Clean up asan_malloc_win.cpp and add exports

ALLOCATION_FUNCTION_ATTRIBUTE wasn't used elsewhere, and was just one
attribute, so abstracting it through a macro wasn't doing much good now that it's
not conditional on runtime type.

We're always in the dynamic runtime now so eliminate the preprocessor conditional.

The new exported functions are the interface used by the intercepted malloc/free family
in the instrumented binary to call the asan versions inside the dll runtime.
---
 compiler-rt/lib/asan/asan_malloc_win.cpp | 97 ++++++++++--------------
 1 file changed, 42 insertions(+), 55 deletions(-)

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(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
 

>From 9004911b297d3f04440a81d0f62615614a701b5f Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:42:30 -0800
Subject: [PATCH 10/15] Weak function interception support in instruction size
 decoder.

---
 compiler-rt/lib/interception/interception_win.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp
index 1829358705fe82..1523374739396d 100644
--- a/compiler-rt/lib/interception/interception_win.cpp
+++ b/compiler-rt/lib/interception/interception_win.cpp
@@ -479,6 +479,8 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
 
   switch (*(u8*)address) {
     case 0x90:  // 90 : nop
+    case 0xC3:  // C3 : ret   (for small/empty function interception
+    case 0xCC:  // CC : int 3  i.e. registering weak functions)
       return 1;
 
     case 0x50:  // push eax / rax
@@ -502,7 +504,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     // Cannot overwrite control-instruction. Return 0 to indicate failure.
     case 0xE9:  // E9 XX XX XX XX : jmp <label>
     case 0xE8:  // E8 XX XX XX XX : call <func>
-    case 0xC3:  // C3 : ret
     case 0xEB:  // EB XX : jmp XX (short jump)
     case 0x70:  // 7Y YY : jy XX (short conditional jump)
     case 0x71:
@@ -545,6 +546,11 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
       return 7;
   }
 
+  switch (0x000000FF & *(u32 *)address) {
+    case 0xc2:  // C2 XX XX : ret XX (needed for registering weak functions)
+      return 3;
+  }
+
 #  if SANITIZER_WINDOWS_x64
   switch (*(u8*)address) {
     case 0xA1:  // A1 XX XX XX XX XX XX XX XX :
@@ -605,6 +611,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     case 0xc18b4c:    // 4C 8B C1 : mov r8, rcx
     case 0xd2b60f:    // 0f b6 d2 : movzx edx, dl
     case 0xca2b48:    // 48 2b ca : sub rcx, rdx
+    case 0xca3b48:    // 48 3b ca : cmp rcx, rdx
     case 0x10b70f:    // 0f b7 10 : movzx edx, WORD PTR [rax]
     case 0xc00b4d:    // 3d 0b c0 : or r8, r8
     case 0xc08b41:    // 41 8b c0 : mov eax, r8d
@@ -624,6 +631,8 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
 
     case 0x058b48:    // 48 8b 05 XX XX XX XX :
                       //   mov rax, QWORD PTR [rip + XXXXXXXX]
+    case 0x058d48:    // 48 8d 05 XX XX XX XX :
+                      //   lea rax, QWORD PTR [rip + XXXXXXXX]
     case 0x25ff48:    // 48 ff 25 XX XX XX XX :
                       //   rex.W jmp QWORD PTR [rip + XXXXXXXX]
     case 0x158D4C:    // 4c 8d 15 XX XX XX XX : lea r10, [rip + XX]

>From 37a2cc945cc48e5cc3ba76ebfc8da2858578f986 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:43:21 -0800
Subject: [PATCH 11/15] add new substitutions to the tests to support the new
 static/dynamic runtime thunks

and the fact we're "always" using the dynamic asan runtime.

python formatting
---
 compiler-rt/test/asan/lit.cfg.py | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py
index 83b3cbe789cacc..4e4233a6534ff4 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

>From 0f9a777eda2efb3d2d711a576ca4a66d44914b35 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 18:46:54 -0800
Subject: [PATCH 12/15] Fixup and enable tests.

Enable a bunch of tests that were previously broken in one or the other runtime configuration.

Fix tests that were looking for particular frame numbers, these moved around because the new
interception methods added a few new frames to the stack.
---
 .../asan/TestCases/Windows/bitfield_uaf.cpp   | 14 ++---
 .../TestCases/Windows/calloc_left_oob.cpp     | 14 ++---
 .../TestCases/Windows/calloc_right_oob.cpp    | 14 ++---
 .../asan/TestCases/Windows/calloc_uaf.cpp     | 20 +++----
 .../TestCases/Windows/defaultlibs_check.cpp   |  8 +++
 .../TestCases/Windows/dll_heap_allocation.cpp |  2 +-
 .../test/asan/TestCases/Windows/dll_host.cpp  | 42 --------------
 .../TestCases/Windows/dll_malloc_left_oob.cpp | 22 ++++----
 .../asan/TestCases/Windows/dll_malloc_uaf.cpp | 30 +++++-----
 .../asan/TestCases/Windows/double_free.cpp    | 20 +++----
 .../TestCases/Windows/free_hook_realloc.cpp   |  3 -
 .../TestCases/Windows/intercept_strdup.cpp    | 26 ++++-----
 .../Windows/interface_symbols_windows.cpp     | 56 -------------------
 .../TestCases/Windows/malloc_left_oob.cpp     | 14 ++---
 .../TestCases/Windows/malloc_right_oob.cpp    | 14 ++---
 .../asan/TestCases/Windows/malloc_uaf.cpp     | 20 +++----
 .../TestCases/Windows/msvc/dll_and_lib.cpp    |  5 +-
 .../Windows/msvc/dll_large_function.cpp       |  3 +-
 .../TestCases/Windows/realloc_left_oob.cpp    | 14 ++---
 .../TestCases/Windows/realloc_right_oob.cpp   | 14 ++---
 .../asan/TestCases/Windows/realloc_uaf.cpp    | 20 +++----
 .../asan/TestCases/Windows/symbols_path.cpp   | 14 ++---
 .../asan/TestCases/Windows/unsymbolized.cpp   |  2 +-
 .../TestCases/Windows/use_after_realloc.cpp   | 20 +++----
 .../test/asan/TestCases/calloc-overflow.cpp   |  2 +-
 .../test/asan/TestCases/debug_double_free.cpp |  3 -
 .../test/asan/TestCases/debug_report.cpp      |  3 -
 .../test/asan/TestCases/deep_stack_uaf.cpp    |  2 +-
 .../test/asan/TestCases/default_options.cpp   |  4 --
 .../test/asan/TestCases/double-free.cpp       |  4 +-
 .../asan/TestCases/malloc-size-too-big.cpp    |  2 +-
 .../test/asan/TestCases/on_error_callback.cpp |  3 -
 .../asan/TestCases/report_error_summary.cpp   |  3 -
 .../test/asan/TestCases/strncpy-overflow.cpp  |  2 +-
 .../asan/TestCases/use-after-free-right.cpp   |  4 +-
 .../test/asan/TestCases/use-after-free.cpp    |  4 +-
 36 files changed, 168 insertions(+), 279 deletions(-)
 create mode 100644 compiler-rt/test/asan/TestCases/Windows/defaultlibs_check.cpp
 delete mode 100644 compiler-rt/test/asan/TestCases/Windows/interface_symbols_windows.cpp

diff --git a/compiler-rt/test/asan/TestCases/Windows/bitfield_uaf.cpp b/compiler-rt/test/asan/TestCases/Windows/bitfield_uaf.cpp
index 8e1a2ae1491486..85310d7ca4e293 100644
--- a/compiler-rt/test/asan/TestCases/Windows/bitfield_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/bitfield_uaf.cpp
@@ -21,13 +21,13 @@ void make_access(S *s) {
 int main(void) {
   S *s = (S*)malloc(sizeof(S));
   free(s);
-// CHECK: [[ADDR]] is located 0 bytes inside of 4-byte region
-// CHECK-LABEL: freed by thread T0 here:
-// CHECK:   {{#0 .* free }}
-// CHECK:   {{#1 .* main .*bitfield_uaf.cpp}}:[[@LINE-4]]
-// CHECK-LABEL: previously allocated by thread T0 here:
-// CHECK:   {{#0 .* malloc }}
-// CHECK:   {{#1 .* main .*bitfield_uaf.cpp}}:[[@LINE-8]]
+  // CHECK: [[ADDR]] is located 0 bytes inside of 4-byte region
+  // CHECK-LABEL: freed by thread T0 here:
+  // CHECK:   {{#0 .* free }}
+  // CHECK:   {{ .* main .*bitfield_uaf.cpp}}:[[@LINE-4]]
+  // CHECK-LABEL: previously allocated by thread T0 here:
+  // CHECK:   {{#0 .* malloc }}
+  // CHECK:   {{.* main .*bitfield_uaf.cpp}}:[[@LINE-8]]
   make_access(s);
   return 0;
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/calloc_left_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/calloc_left_oob.cpp
index b22c359b3dc42f..06c764eab5dd3f 100644
--- a/compiler-rt/test/asan/TestCases/Windows/calloc_left_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/calloc_left_oob.cpp
@@ -6,12 +6,12 @@
 int main() {
   int *buffer = (int*)calloc(42, sizeof(int));
   buffer[-1] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 4 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*calloc_left_oob.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 4 bytes before 168-byte region
-// CHECK: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* calloc }}
-// CHECK-NEXT: {{#1 .* main .*calloc_left_oob.cpp}}:[[@LINE-8]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 4 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*calloc_left_oob.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 4 bytes before 168-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK: {{#0 .* calloc }}
+  // CHECK: {{.* main .*calloc_left_oob.cpp}}:[[@LINE-8]]
   free(buffer);
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/calloc_right_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/calloc_right_oob.cpp
index 9e12f9cf653e09..420c6f2736c613 100644
--- a/compiler-rt/test/asan/TestCases/Windows/calloc_right_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/calloc_right_oob.cpp
@@ -6,12 +6,12 @@
 int main() {
   int *buffer = (int*)calloc(42, sizeof(int));
   buffer[42] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 4 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*calloc_right_oob.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 0 bytes after 168-byte region
-// CHECK: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* calloc }}
-// CHECK-NEXT: {{#1 .* main .*calloc_right_oob.cpp}}:[[@LINE-8]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 4 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*calloc_right_oob.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 0 bytes after 168-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* calloc }}
+  // CHECK: {{ .* main .*calloc_right_oob.cpp}}:[[@LINE-8]]
   free(buffer);
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/calloc_uaf.cpp b/compiler-rt/test/asan/TestCases/Windows/calloc_uaf.cpp
index 6c225d4c676d08..6830232e2b81fd 100644
--- a/compiler-rt/test/asan/TestCases/Windows/calloc_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/calloc_uaf.cpp
@@ -7,14 +7,14 @@ int main() {
   int *buffer = (int*)calloc(42, sizeof(int));
   free(buffer);
   buffer[0] = 42;
-// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 4 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*calloc_uaf.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region
-// CHECK: freed by thread T0 here:
-// CHECK-NEXT: {{#0 .* free }}
-// CHECK-NEXT: {{#1 .* main .*calloc_uaf.cpp}}:[[@LINE-8]]
-// CHECK: previously allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* calloc }}
-// CHECK-NEXT: {{#1 .* main .*calloc_uaf.cpp}}:[[@LINE-12]]
+  // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 4 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*calloc_uaf.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region
+  // CHECK: freed by thread T0 here:
+  // CHECK-NEXT: {{#0 .* free }}
+  // CHECK: {{.* main .*calloc_uaf.cpp}}:[[@LINE-8]]
+  // CHECK: previously allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* calloc }}
+  // CHECK: {{.* main .*calloc_uaf.cpp}}:[[@LINE-12]]
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/defaultlibs_check.cpp b/compiler-rt/test/asan/TestCases/Windows/defaultlibs_check.cpp
new file mode 100644
index 00000000000000..d69f0b2ebb43df
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/Windows/defaultlibs_check.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cl_asan -Od %s -Fe%t /link /WX
+// RUN: %clang_cl_asan -Od %s -Fe%t /link /WX /INFERASANLIBS:DEBUG
+
+// Link with /WX under each configuration to ensure there are
+// no warnings (ex: defaultlib mismatch, pragma detect mismatch)
+// when linking.
+
+int main() { return 0; }
\ No newline at end of file
diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_heap_allocation.cpp b/compiler-rt/test/asan/TestCases/Windows/dll_heap_allocation.cpp
index b8c2c1a24d4ce0..3606b1c8163171 100644
--- a/compiler-rt/test/asan/TestCases/Windows/dll_heap_allocation.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/dll_heap_allocation.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cl %LD %s %Fe%t.dll -DHEAP_LIBRARY %MD \
 // RUN:   %if target={{.*-windows-gnu}} %{ -Wl,--out-implib,%t.lib %}
-// RUN: %clang_cl %s %t.lib %Fe%t -fsanitize=address %MT
+// RUN: %clang_cl_asan %s %t.lib %Fe%t
 // RUN: %run %t 2>&1 | FileCheck %s
 
 // Check that ASan does not fail when releasing allocations that occurred within
diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_host.cpp b/compiler-rt/test/asan/TestCases/Windows/dll_host.cpp
index 0757af90d211c3..85b7967e86b510 100644
--- a/compiler-rt/test/asan/TestCases/Windows/dll_host.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/dll_host.cpp
@@ -5,48 +5,6 @@
 // Just make sure we can compile this.
 // The actual compile&run sequence is to be done by the DLL tests.
 // RUN: %clang_cl_asan -Od %s -Fe%t
-//
-// Get the list of ASan wrappers exported by the main module RTL:
-// note: The mangling decoration (i.e. @4 )is removed because calling convention
-//       differ from 32-bit and 64-bit.
-// RUN: dumpbin /EXPORTS %t | grep -o "__asan_wrap[^ ]*" | sed -e s/@.*// > %t.exports1
-//
-// The exception handlers differ in 32-bit and 64-bit, so we ignore them:
-// RUN: grep '[E]XPORT:' %s | sed -e 's/.*[E]XPORT: //' > %t.exports2
-// EXPORT: __asan_wrap__except_handler3
-// EXPORT: __asan_wrap__except_handler4
-// EXPORT: __asan_wrap___C_specific_handler
-//
-// Get the list of ASan wrappers imported by the DLL RTL:
-// [BEWARE: be really careful with the sed commands, as this test can be run
-//  from different environments with different shells and seds]
-// RUN: grep INTERCEPT_LIBRARY_FUNCTION %p/../../../../lib/asan/asan_win_dll_thunk.cpp \
-// RUN:  | grep -v define | sed -e s/.*(/__asan_wrap_/ -e s/).*//              \
-// RUN:  > %t.imports1
-//
-// Add functions interecepted in asan_malloc.win.cpp and asan_win.cpp.
-// RUN: grep '[I]MPORT:' %s | sed -e 's/.*[I]MPORT: //' > %t.imports2
-// IMPORT: __asan_wrap_HeapAlloc
-// IMPORT: __asan_wrap_HeapFree
-// IMPORT: __asan_wrap_HeapReAlloc
-// IMPORT: __asan_wrap_HeapSize
-// IMPORT: __asan_wrap_CreateThread
-// IMPORT: __asan_wrap_RaiseException
-// IMPORT: __asan_wrap_RtlRaiseException
-// IMPORT: __asan_wrap_SetUnhandledExceptionFilter
-// IMPORT: __asan_wrap_RtlSizeHeap
-// IMPORT: __asan_wrap_RtlAllocateHeap
-// IMPORT: __asan_wrap_RtlReAllocateHeap
-// IMPORT: __asan_wrap_RtlFreeHeap
-//
-// RUN: cat %t.imports1 %t.imports2 | sort | uniq > %t.imports-sorted
-// RUN: cat %t.exports1 %t.exports2 | sort | uniq > %t.exports-sorted
-//
-// Now make sure the DLL thunk imports everything:
-// RUN: echo
-// RUN: echo "=== NOTE === If you see a mismatch below, please update asan_win_dll_thunk.cpp"
-// RUN: diff %t.imports-sorted %t.exports-sorted
-// REQUIRES: asan-static-runtime
 
 #include <stdio.h>
 #include <windows.h>
diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_malloc_left_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/dll_malloc_left_oob.cpp
index 6d550eb966cda3..5ca48fbd683840 100644
--- a/compiler-rt/test/asan/TestCases/Windows/dll_malloc_left_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/dll_malloc_left_oob.cpp
@@ -7,17 +7,17 @@ extern "C" __declspec(dllexport)
 int test_function() {
   char *buffer = (char*)malloc(42);
   buffer[-1] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cpp:[[@LINE-3]]
-// CHECK-NEXT: main {{.*}}dll_host.cpp
-//
-// CHECK: [[ADDR]] is located 1 bytes before 42-byte region
-// CHECK-LABEL: allocated by thread T0 here:
-// CHECK-NEXT:   malloc
-// CHECK-NEXT:   test_function {{.*}}dll_malloc_left_oob.cpp:[[@LINE-10]]
-// CHECK-NEXT:   main {{.*}}dll_host.cpp
-// CHECK-LABEL: SUMMARY
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cpp:[[@LINE-3]]
+  // CHECK-NEXT: main {{.*}}dll_host.cpp
+  //
+  // CHECK: [[ADDR]] is located 1 bytes before 42-byte region
+  // CHECK-LABEL: allocated by thread T0 here:
+  // CHECK-NEXT:   malloc
+  // CHECK:   test_function {{.*}}dll_malloc_left_oob.cpp:[[@LINE-10]]
+  // CHECK-NEXT:   main {{.*}}dll_host.cpp
+  // CHECK-LABEL: SUMMARY
   free(buffer);
   return 0;
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_malloc_uaf.cpp b/compiler-rt/test/asan/TestCases/Windows/dll_malloc_uaf.cpp
index bc701e92961c99..ae23f86d7ddf49 100644
--- a/compiler-rt/test/asan/TestCases/Windows/dll_malloc_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/dll_malloc_uaf.cpp
@@ -9,20 +9,20 @@ int test_function() {
   int *buffer = (int*)malloc(42);
   free(buffer);
   buffer[0] = 42;
-// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 4 at [[ADDR]] thread T0
-// CHECK-NEXT:  test_function {{.*}}dll_malloc_uaf.cpp:[[@LINE-3]]
-// CHECK-NEXT:  main {{.*}}dll_host
-//
-// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
-// CHECK-LABEL: freed by thread T0 here:
-// CHECK-NEXT:  free
-// CHECK-NEXT:  test_function {{.*}}dll_malloc_uaf.cpp:[[@LINE-10]]
-// CHECK-NEXT:  main {{.*}}dll_host
-//
-// CHECK-LABEL: previously allocated by thread T0 here:
-// CHECK-NEXT:  malloc
-// CHECK-NEXT:  test_function {{.*}}dll_malloc_uaf.cpp:[[@LINE-16]]
-// CHECK-NEXT:  main {{.*}}dll_host
+  // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 4 at [[ADDR]] thread T0
+  // CHECK-NEXT:  test_function {{.*}}dll_malloc_uaf.cpp:[[@LINE-3]]
+  // CHECK-NEXT:  main {{.*}}dll_host
+  //
+  // CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
+  // CHECK-LABEL: freed by thread T0 here:
+  // CHECK-NEXT:  free
+  // CHECK:  test_function {{.*}}dll_malloc_uaf.cpp:[[@LINE-10]]
+  // CHECK-NEXT:  main {{.*}}dll_host
+  //
+  // CHECK-LABEL: previously allocated by thread T0 here:
+  // CHECK-NEXT:  malloc
+  // CHECK:  test_function {{.*}}dll_malloc_uaf.cpp:[[@LINE-16]]
+  // CHECK-NEXT:  main {{.*}}dll_host
   return 0;
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/double_free.cpp b/compiler-rt/test/asan/TestCases/Windows/double_free.cpp
index 45568e50d0c824..c7299094a1cbf7 100644
--- a/compiler-rt/test/asan/TestCases/Windows/double_free.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/double_free.cpp
@@ -7,15 +7,15 @@ int main() {
   int *x = (int*)malloc(42 * sizeof(int));
   free(x);
   free(x);
-// CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]]
-// CHECK-NEXT: {{#0 .* free }}
-// CHECK-NEXT: {{#1 .* 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-NEXT: {{#1 .* main .*double_free.cpp}}:[[@LINE-8]]
-// CHECK-LABEL: previously allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* malloc }}
-// CHECK-NEXT: {{#1 .* main .*double_free.cpp}}:[[@LINE-12]]
+  // CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]]
+  // CHECK-NEXT: {{#0 .* free }}
+  // CHECK: {{.* 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: {{.* main .*double_free.cpp}}:[[@LINE-8]]
+  // CHECK-LABEL: previously allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* malloc }}
+  // CHECK: {{.* 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 11e8c9975cf3bf..297218bf8e99f1 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 <stdlib.h>
 #include <io.h>
 #include <sanitizer/allocator_interface.h>
diff --git a/compiler-rt/test/asan/TestCases/Windows/intercept_strdup.cpp b/compiler-rt/test/asan/TestCases/Windows/intercept_strdup.cpp
index b519f53fe42698..fec4d1ec35597c 100644
--- a/compiler-rt/test/asan/TestCases/Windows/intercept_strdup.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/intercept_strdup.cpp
@@ -15,18 +15,18 @@ int main() {
 
   subscript = -1;
   ptr[subscript] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK:   {{#0 .* main .*}}intercept_strdup.cpp:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 1 bytes before 6-byte region
-// CHECK: allocated by thread T0 here:
-//
-// The first frame is our wrapper normally but will be malloc in the dynamic
-// config.
-// CHECK:   #0 {{.*}} in {{malloc|strdup}}
-//
-// The local call to _strdup above may be the second or third frame depending
-// on whether we're using the dynamic config.
-// CHECK:   #{{[12]}} {{.*}} in main {{.*}}intercept_strdup.cpp:[[@LINE-21]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK:   {{#0 .* main .*}}intercept_strdup.cpp:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 1 bytes before 6-byte region
+  // CHECK: allocated by thread T0 here:
+  //
+  // The first frame is our wrapper normally but will be malloc in the dynamic
+  // config.
+  // CHECK:   #0 {{.*}} in {{malloc|_strdup}}
+  //
+  // The local call to _strdup above may be the second or third frame depending
+  // on whether we're using the dynamic config.
+  // CHECK:   #{{[12]}} {{.*}} in main {{.*}}intercept_strdup.cpp:[[@LINE-21]]
   free(ptr);
 }
diff --git a/compiler-rt/test/asan/TestCases/Windows/interface_symbols_windows.cpp b/compiler-rt/test/asan/TestCases/Windows/interface_symbols_windows.cpp
deleted file mode 100644
index 1803911a43a9b0..00000000000000
--- a/compiler-rt/test/asan/TestCases/Windows/interface_symbols_windows.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-// UNSUPPORTED: target={{.*-windows-gnu}}
-
-// Check that the interface exported by asan static lib matches the list of
-// functions mentioned in sanitizer_interface.inc.
-//
-// Just make sure we can compile this.
-// RUN: %clang_cl_asan -Od %s -Fe%t
-//
-// note: The mangling decoration (i.e. @4 )is removed because calling convention
-//       differ from 32-bit and 64-bit.
-//
-// RUN: dumpbin /EXPORTS %t | sed "s/=.*//"                                    \
-// RUN:   | grep -o "\(__asan_\|__ubsan_\|__sanitizer_\|__sancov_\)[^ ]*"      \
-// RUN:   | grep -v "__asan_wrap"                                              \
-// RUN:   | sed -e s/@.*// > %t.exports
-//
-// [BEWARE: be really careful with the sed commands, as this test can be run
-//  from different environments with different shells and seds]
-//
-// RUN: sed ':a;N;$!ba;s/([\n ]*/(/g'                                          \
-// RUN:  %p/../../../../lib/asan/asan_interface.inc                            \
-// RUN:  %p/../../../../lib/ubsan/ubsan_interface.inc                          \
-// RUN:  %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc    \
-// RUN:  %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc  \
-// RUN:  | grep -e "^INTERFACE_FUNCTION"                                       \
-// RUN:  | sed -e "s/.*(//" -e "s/).*//" > %t.imports1
-//
-// RUN: sed ':a;N;$!ba;s/([\n ]*/(/g'                                          \
-// RUN:  %p/../../../../lib/asan/asan_interface.inc                            \
-// RUN:  %p/../../../../lib/ubsan/ubsan_interface.inc                          \
-// RUN:  %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc    \
-// RUN:  %p/../../../../lib/sanitizer_common/sanitizer_coverage_interface.inc  \
-// RUN:  | grep -e "^INTERFACE_WEAK_FUNCTION"                                  \
-// RUN:  | sed -e "s/.*(//" -e "s/).*/__dll/" > %t.imports2
-//
-// Add functions not included in the interface lists:
-// RUN: grep '[I]MPORT:' %s | sed -e 's/.*[I]MPORT: //' > %t.imports3
-// IMPORT: __asan_shadow_memory_dynamic_address
-// IMPORT: __asan_get_shadow_memory_dynamic_address
-// IMPORT: __asan_option_detect_stack_use_after_return
-// IMPORT: __asan_should_detect_stack_use_after_return
-// IMPORT: __asan_set_seh_filter
-// IMPORT: __asan_unhandled_exception_filter
-// IMPORT: __asan_test_only_reported_buggy_pointer
-// IMPORT: __ubsan_vptr_type_cache
-//
-// RUN: cat %t.imports1 %t.imports2 %t.imports3 | sort | uniq > %t.imports-sorted
-// RUN: cat %t.exports | sort | uniq > %t.exports-sorted
-//
-// Now make sure the DLL thunk imports everything:
-// RUN: echo
-// RUN: echo "=== NOTE === If you see a mismatch below, please update interface.inc files."
-// RUN: diff %t.imports-sorted %t.exports-sorted
-// REQUIRES: asan-static-runtime
-
-int main() { return 0; }
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 2ee5fdc7abee2f..fb1ccf5f21b745 100644
--- a/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp
@@ -6,12 +6,12 @@
 int main() {
   char *buffer = (char*)malloc(42);
   buffer[-1] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*malloc_left_oob.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 1 bytes before 42-byte region
-// CHECK: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* malloc }}
-// CHECK-NEXT: {{#1 .* main .*malloc_left_oob.cpp}}:[[@LINE-8]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*malloc_left_oob.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 1 bytes before 42-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* malloc }}
+  // CHECK: {{ .* 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 dafca74b4812da..0b9b400cacc4c2 100644
--- a/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp
@@ -6,12 +6,12 @@
 int main() {
   char *buffer = (char*)malloc(42);
   buffer[42] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*malloc_right_oob.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 0 bytes after 42-byte region
-// CHECK: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* malloc }}
-// CHECK-NEXT: {{#1 .* main .*malloc_right_oob.cpp}}:[[@LINE-8]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*malloc_right_oob.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 0 bytes after 42-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* malloc }}
+  // CHECK: {{ .* 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 256582deefe46e..4ffe3b53909c35 100644
--- a/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp
@@ -7,14 +7,14 @@ int main() {
   char *buffer = (char*)malloc(42);
   free(buffer);
   buffer[0] = 42;
-// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*malloc_uaf.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
-// CHECK: freed by thread T0 here:
-// CHECK-NEXT: {{#0 .* free }}
-// CHECK-NEXT: {{#1 .* main .*malloc_uaf.cpp}}:[[@LINE-8]]
-// CHECK: previously allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* malloc }}
-// CHECK-NEXT: {{#1 .* main .*malloc_uaf.cpp}}:[[@LINE-12]]
+  // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*malloc_uaf.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
+  // CHECK: freed by thread T0 here:
+  // CHECK-NEXT: {{#0 .* free }}
+  // CHECK: {{ .* main .*malloc_uaf.cpp}}:[[@LINE-8]]
+  // CHECK: previously allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* malloc }}
+  // CHECK: {{ .* 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 96fae6b1d60392..175bdefa7c995d 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 788488dbb8ed82..f0c3deabbcf970 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 4a5a7ab8ecfdfb..8d31b206e44719 100644
--- a/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp
@@ -6,12 +6,12 @@
 int main() {
   char *buffer = (char*)realloc(0, 42);
   buffer[-1] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*realloc_left_oob.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 1 bytes before 42-byte region
-// CHECK: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* realloc }}
-// CHECK-NEXT: {{#1 .* main .*realloc_left_oob.cpp}}:[[@LINE-8]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*realloc_left_oob.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 1 bytes before 42-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* realloc }}
+  // CHECK: {{ .* 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 8f3109eed2d079..355767ca1050bb 100644
--- a/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp
@@ -6,12 +6,12 @@
 int main() {
   char *buffer = (char*)realloc(0, 42);
   buffer[42] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*realloc_right_oob.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 0 bytes after 42-byte region
-// CHECK: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* realloc }}
-// CHECK-NEXT: {{#1 .* main .*realloc_right_oob.cpp}}:[[@LINE-8]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*realloc_right_oob.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 0 bytes after 42-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* realloc }}
+  // CHECK: {{ .* 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 074ac270f13f5c..f0b119a6b6af81 100644
--- a/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp
@@ -7,14 +7,14 @@ int main() {
   char *buffer = (char*)realloc(0, 42);
   free(buffer);
   buffer[0] = 42;
-// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*realloc_uaf.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
-// CHECK: freed by thread T0 here:
-// CHECK-NEXT: {{#0 .* free }}
-// CHECK-NEXT: {{#1 .* main .*realloc_uaf.cpp}}:[[@LINE-8]]
-// CHECK: previously allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* realloc }}
-// CHECK-NEXT: {{#1 .* main .*realloc_uaf.cpp}}:[[@LINE-12]]
+  // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*realloc_uaf.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
+  // CHECK: freed by thread T0 here:
+  // CHECK-NEXT: {{#0 .* free }}
+  // CHECK: {{ .* main .*realloc_uaf.cpp}}:[[@LINE-8]]
+  // CHECK: previously allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* realloc }}
+  // CHECK: {{ .* 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 d896da482f2ebc..7b74f03290ecc6 100644
--- a/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp
@@ -11,12 +11,12 @@
 int main() {
   char *buffer = (char*)malloc(42);
   buffer[-1] = 42;
-// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*symbols_path.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 1 bytes before 42-byte region
-// CHECK: allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* malloc}}
-// CHECK-NEXT: {{#1 .* main .*symbols_path.cpp}}:[[@LINE-8]]
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*symbols_path.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 1 bytes before 42-byte region
+  // CHECK: allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* malloc}}
+  // CHECK: {{ .* 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 0eb1e9ee91b0a7..00428b809fccd7 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 dfd25cebb6bfef..34cecf5fc63d3a 100644
--- a/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp
@@ -9,15 +9,15 @@ int main() {
   buffer = (char*)realloc(buffer, 64);
   // The 'stale' may now point to a free'd memory.
   stale[0] = 42;
-// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
-// CHECK: WRITE of size 1 at [[ADDR]] thread T0
-// CHECK-NEXT: {{#0 .* main .*use_after_realloc.cpp}}:[[@LINE-3]]
-// CHECK: [[ADDR]] is located 0 bytes inside of 32-byte region
-// CHECK: freed by thread T0 here:
-// CHECK-NEXT: {{#0 .* realloc }}
-// CHECK-NEXT: {{#1 .* main .*use_after_realloc.cpp}}:[[@LINE-9]]
-// CHECK: previously allocated by thread T0 here:
-// CHECK-NEXT: {{#0 .* realloc }}
-// CHECK-NEXT: {{#1 .* main .*use_after_realloc.cpp}}:[[@LINE-14]]
+  // CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
+  // CHECK-NEXT: {{#0 .* main .*use_after_realloc.cpp}}:[[@LINE-3]]
+  // CHECK: [[ADDR]] is located 0 bytes inside of 32-byte region
+  // CHECK: freed by thread T0 here:
+  // CHECK-NEXT: {{#0 .* realloc }}
+  // CHECK: {{ .* main .*use_after_realloc.cpp}}:[[@LINE-9]]
+  // CHECK: previously allocated by thread T0 here:
+  // CHECK-NEXT: {{#0 .* realloc }}
+  // CHECK: {{ .* main .*use_after_realloc.cpp}}:[[@LINE-14]]
   free(buffer);
 }
diff --git a/compiler-rt/test/asan/TestCases/calloc-overflow.cpp b/compiler-rt/test/asan/TestCases/calloc-overflow.cpp
index 9a0d41ff826018..b930b65cd8c3b0 100644
--- a/compiler-rt/test/asan/TestCases/calloc-overflow.cpp
+++ b/compiler-rt/test/asan/TestCases/calloc-overflow.cpp
@@ -11,7 +11,7 @@ int main() {
   void *p = calloc(-1, 1000);
   // CHECK: {{ERROR: AddressSanitizer: calloc parameters overflow: count \* size \(.* \* 1000\) cannot be represented in type size_t}}
   // CHECK: {{#0 0x.* in .*calloc}}
-  // CHECK: {{#1 0x.* in main .*calloc-overflow.cpp:}}[[@LINE-3]]
+  // CHECK: {{#[1-3] 0x.* in main .*calloc-overflow.cpp:}}[[@LINE-3]]
   // CHECK: SUMMARY: AddressSanitizer: calloc-overflow
 
   printf("calloc returned: %zu\n", (size_t)p);
diff --git a/compiler-rt/test/asan/TestCases/debug_double_free.cpp b/compiler-rt/test/asan/TestCases/debug_double_free.cpp
index de5ac7b0c8d5cd..8a2ce40bc561f6 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 <stdio.h>
 #include <stdlib.h>
 
-// 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 617b7ee91e18d7..855642bdc0d3bb 100644
--- a/compiler-rt/test/asan/TestCases/debug_report.cpp
+++ b/compiler-rt/test/asan/TestCases/debug_report.cpp
@@ -6,9 +6,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-// 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/deep_stack_uaf.cpp b/compiler-rt/test/asan/TestCases/deep_stack_uaf.cpp
index bdf0dbdb4a4bd0..7d8a09220689f5 100644
--- a/compiler-rt/test/asan/TestCases/deep_stack_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/deep_stack_uaf.cpp
@@ -1,7 +1,7 @@
 // Check that we can store lots of stack frames if asked to.
 
 // RUN: %clangxx_asan -O0 %s -o %t 2>&1
-// RUN: %env_asan_opts=malloc_context_size=120:redzone=512 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=malloc_context_size=125:redzone=512 not %run %t 2>&1 | FileCheck %s
 // REQUIRES: stable-runtime
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/compiler-rt/test/asan/TestCases/default_options.cpp b/compiler-rt/test/asan/TestCases/default_options.cpp
index 526dab6450e9bd..845e8a5f1793e4 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/double-free.cpp b/compiler-rt/test/asan/TestCases/double-free.cpp
index b01e41005a27a3..7b61df0715afaf 100644
--- a/compiler-rt/test/asan/TestCases/double-free.cpp
+++ b/compiler-rt/test/asan/TestCases/double-free.cpp
@@ -19,10 +19,10 @@ int main(int argc, char **argv) {
   free(x + argc - 1);  // BOOM
   // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
   // CHECK: #0 0x{{.*}} in {{.*}}free
-  // CHECK: #1 0x{{.*}} in main {{.*}}double-free.cpp:[[@LINE-3]]
+  // CHECK: #{{[1-3]}} 0x{{.*}} in main {{.*}}double-free.cpp:[[@LINE-3]]
   // CHECK: freed by thread T0 here:
   // MALLOC-CTX: #0 0x{{.*}} in {{.*}}free
-  // MALLOC-CTX: #1 0x{{.*}} in main {{.*}}double-free.cpp:[[@LINE-7]]
+  // MALLOC-CTX: #{{[1-3]}} 0x{{.*}} in main {{.*}}double-free.cpp:[[@LINE-7]]
   // CHECK: allocated by thread T0 here:
   // MALLOC-CTX: double-free.cpp:[[@LINE-12]]
   // CHECK-RECOVER: AddressSanitizer: attempting double-free{{.*}}in thread T0
diff --git a/compiler-rt/test/asan/TestCases/malloc-size-too-big.cpp b/compiler-rt/test/asan/TestCases/malloc-size-too-big.cpp
index 71d6a3e7148a3e..771640a4ac08d1 100644
--- a/compiler-rt/test/asan/TestCases/malloc-size-too-big.cpp
+++ b/compiler-rt/test/asan/TestCases/malloc-size-too-big.cpp
@@ -18,7 +18,7 @@ int main() {
   void *p = malloc(kMaxAllowedMallocSizePlusOne);
   // CHECK: {{ERROR: AddressSanitizer: requested allocation size .* \(.* after adjustments for alignment, red zones etc\.\) exceeds maximum supported size}}
   // CHECK: {{#0 0x.* in .*malloc}}
-  // CHECK: {{#1 0x.* in main .*malloc-size-too-big.cpp:}}[[@LINE-3]]
+  // CHECK: {{#[1-3] 0x.* in main .*malloc-size-too-big.cpp:}}[[@LINE-3]]
   // CHECK: SUMMARY: AddressSanitizer: allocation-size-too-big
 
   printf("malloc returned: %zu\n", (size_t)p);
diff --git a/compiler-rt/test/asan/TestCases/on_error_callback.cpp b/compiler-rt/test/asan/TestCases/on_error_callback.cpp
index f65a8f1abe8310..c38a36f0e33bda 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 <stdio.h>
 #include <stdlib.h>
 
diff --git a/compiler-rt/test/asan/TestCases/report_error_summary.cpp b/compiler-rt/test/asan/TestCases/report_error_summary.cpp
index d565d2add77934..9e024e35bed864 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 <stdio.h>
 
 // Required for ld64 macOS 12.0+
diff --git a/compiler-rt/test/asan/TestCases/strncpy-overflow.cpp b/compiler-rt/test/asan/TestCases/strncpy-overflow.cpp
index d852ccebd9a778..ff84052a94987a 100644
--- a/compiler-rt/test/asan/TestCases/strncpy-overflow.cpp
+++ b/compiler-rt/test/asan/TestCases/strncpy-overflow.cpp
@@ -33,6 +33,6 @@ int main(int argc, char **argv) {
   // CHECK: {{0x.* is located 0 bytes after 9-byte region}}
   // CHECK: {{allocated by thread T0 here:}}
   // CHECK: {{    #0 0x.* in .*malloc}}
-  // CHECK: {{    #1 0x.* in main .*strncpy-overflow.cpp:}}[[@LINE-8]]
+  // CHECK: {{    #[1-3] 0x.* in main .*strncpy-overflow.cpp:}}[[@LINE-8]]
   return rval + sink_memory(9, short_buffer);
 }
diff --git a/compiler-rt/test/asan/TestCases/use-after-free-right.cpp b/compiler-rt/test/asan/TestCases/use-after-free-right.cpp
index 10dbe5b9056848..11011e4b4fb1aa 100644
--- a/compiler-rt/test/asan/TestCases/use-after-free-right.cpp
+++ b/compiler-rt/test/asan/TestCases/use-after-free-right.cpp
@@ -19,9 +19,9 @@ int main() {
   // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}}
   // CHECK: {{freed by thread T0 here:}}
   // CHECK: {{    #0 0x.* in .*free}}
-  // CHECK: {{    #1 0x.* in main .*use-after-free-right.cpp:}}[[@LINE-9]]
+  // CHECK: {{    #[1-3] 0x.* in main .*use-after-free-right.cpp:}}[[@LINE-9]]
 
   // CHECK: {{previously allocated by thread T0 here:}}
   // CHECK: {{    #0 0x.* in .*malloc}}
-  // CHECK: {{    #1 0x.* in main .*use-after-free-right.cpp:}}[[@LINE-14]]
+  // CHECK: {{    #[1-3] 0x.* in main .*use-after-free-right.cpp:}}[[@LINE-14]]
 }
diff --git a/compiler-rt/test/asan/TestCases/use-after-free.cpp b/compiler-rt/test/asan/TestCases/use-after-free.cpp
index 4b20ee25500c06..f19c461960d36a 100644
--- a/compiler-rt/test/asan/TestCases/use-after-free.cpp
+++ b/compiler-rt/test/asan/TestCases/use-after-free.cpp
@@ -16,11 +16,11 @@ int main() {
   // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}}
   // CHECK: {{freed by thread T0 here:}}
   // CHECK: {{    #0 0x.* in .*free}}
-  // CHECK: {{    #1 0x.* in main .*use-after-free.cpp:}}[[@LINE-9]]
+  // CHECK: {{    #[1-3] 0x.* in main .*use-after-free.cpp:}}[[@LINE-9]]
 
   // CHECK: {{previously allocated by thread T0 here:}}
   // CHECK: {{    #0 0x.* in .*malloc}}
-  // CHECK: {{    #1 0x.* in main .*use-after-free.cpp:}}[[@LINE-14]]
+  // CHECK: {{    #[1-3] 0x.* in main .*use-after-free.cpp:}}[[@LINE-14]]
   // CHECK: Shadow byte legend (one shadow byte represents {{[0-9]+}} application bytes):
   // CHECK: Global redzone:
   // CHECK: ASan internal:

>From e7126d5e535e66d1c1d093595a3aaed681ebd16e Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 12 Feb 2024 19:25:07 -0800
Subject: [PATCH 13/15] intercept atoll for the static runtime.

---
 compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
index 3aa90421962be4..dec50a5e1d4d9e 100644
--- a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
@@ -34,6 +34,7 @@
 
 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

>From de28c75266d883d3d85a7a64c1494abfe44fa347 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Fri, 16 Feb 2024 11:15:38 -0800
Subject: [PATCH 14/15] Remove sanitizer_win_dll_thunk.h from the build

---
 compiler-rt/lib/sanitizer_common/CMakeLists.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 9e529ff8ec3ddd..53bbc0408df3f3 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -210,7 +210,6 @@ set(SANITIZER_IMPL_HEADERS
   sanitizer_vector.h
   sanitizer_win.h
   sanitizer_win_defs.h
-  sanitizer_win_dll_thunk.h
   sanitizer_win_interception.h
   sanitizer_win_thunk_interception.h
   )

>From 007edf11a091f41c5243f5a10c7305aab2b9a08e Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Fri, 16 Feb 2024 11:24:45 -0800
Subject: [PATCH 15/15] exclude windows specific interface symbols from
 linux/darwin tests.

---
 .../test/asan/TestCases/Darwin/interface_symbols_darwin.cpp    | 3 +++
 .../test/asan/TestCases/Linux/interface_symbols_linux.cpp      | 3 +++
 2 files changed, 6 insertions(+)

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 2cedbc722c4635..59dca32672901a 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 ce1255c9578317..2d729497548d90 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



More information about the llvm-commits mailing list