[clang] [compiler-rt] Reland [asan][windows] Eliminate the static asan runtime on windows (PR #107899)
Charlie Barto via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 9 11:31:27 PDT 2024
https://github.com/barcharcraz created https://github.com/llvm/llvm-project/pull/107899
This reapplies 8fa66c6ca7272268747835a0e86805307b62399c ([asan][windows] Eliminate the static asan runtime on windows) for a second time.
That PR bounced off the tests because it caused failures in the other sanitizer runtimes, these have been fixed by only building interception, sanitizer_common, and asan with /MD, and continuing to build the rest of the runtimes with /MT. This does mean that any usage of the static ubsan/fuzzer/etc runtimes will mean you're mixing different runtime library linkages in the same app, the interception, sanitizer_common, and asan runtimes are designed for this, however it does result in some linker warnings.
Additionally, it turns out when building in release-mode with LLVM_ENABLE_PDBs the build system forced /OPT:ICF. This totally breaks asan's "new" method of doing "weak" functions on windows, and so /OPT:NOICF was explicitly added to asan's link flags.
>From 4c0769ce7af84600de069cb25e9ba5ceda7affa8 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 01/23] 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)
Co-authored-by: Amy Wishnousky <amyw at microsoft.com>
---
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 57914c3175e815..8e5a838779f67f 100644
--- a/compiler-rt/CMakeLists.txt
+++ b/compiler-rt/CMakeLists.txt
@@ -381,8 +381,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 d51cbaa10a61f9ba3e99883bc71e75403abf582a 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 02/23] 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.
Co-Authored-By: Amy Wishnousky <amyw at microsoft.com>
---
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_dll_thunk.cpp | 20 --
... sanitizer_coverage_win_runtime_thunk.cpp} | 21 +-
...nitizer_coverage_win_weak_interception.cpp | 23 --
.../sanitizer_win_dll_thunk.h | 181 --------------
.../sanitizer_win_immortalize.h | 71 ++++++
.../sanitizer_win_interception.cpp | 156 ++++++++++++
.../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 --
26 files changed, 1083 insertions(+), 813 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
delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dll_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 463ea233b37aa4..f992419c6d9822 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 9442cc35d5ab74..2b59595dcd3bf9 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 35871a942a7a12..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 66f2d259aa5fd4..439bf821273871 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
@@ -207,7 +208,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(..)
@@ -301,57 +303,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 d5981a38ff2921..91be9e9dcc4551 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
@@ -51,3 +51,9 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_ignore_free_hook)
INTERFACE_FUNCTION(__sanitizer_internal_memcpy)
INTERFACE_FUNCTION(__sanitizer_internal_memmove)
INTERFACE_FUNCTION(__sanitizer_internal_memset)
+
+#if SANITIZER_WINDOWS
+INTERFACE_FUNCTION(__sanitizer_override_function)
+INTERFACE_FUNCTION(__sanitizer_override_function_by_addr)
+INTERFACE_FUNCTION(__sanitizer_register_weak_function)
+#endif
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp
deleted file mode 100644
index d0bf8a4556436c..00000000000000
--- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-//===-- sanitizer_coverage_win_dll_thunk.cpp ------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a family of thunks that should be statically linked into
-// the DLLs that have instrumentation in order to delegate the calls to the
-// shared runtime that lives in the main binary.
-// See https://github.com/google/sanitizers/issues/209 for the details.
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DLL_THUNK
-#include "sanitizer_win_dll_thunk.h"
-// Sanitizer Coverage interface functions.
-#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "sanitizer_coverage_interface.inc"
-#endif // SANITIZER_DLL_THUNK
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp
similarity index 59%
rename from compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp
rename to compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp
index 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..808cd2f771fe1e
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h
@@ -0,0 +1,71 @@
+//===-- sanitizer_win_immortalize.h ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer, and interception.
+//
+// Windows-specific thread-safe and pre-CRT global initialization safe
+// infrastructure to create an object whose destructor is never called.
+//===----------------------------------------------------------------------===//
+#if SANITIZER_WINDOWS
+# pragma once
+// Requires including sanitizer_placement_new.h (which is not allowed to be
+// included in headers).
+
+# include "sanitizer_win_defs.h"
+// These types are required to satisfy XFG which requires that the names of the
+// types for indirect calls to be correct as well as the name of the original
+// type for any typedefs.
+
+// TODO: There must be a better way to do this
+# ifndef _WINDOWS_
+typedef void* PVOID;
+typedef int BOOL;
+typedef union _RTL_RUN_ONCE {
+ PVOID ptr;
+} INIT_ONCE, *PINIT_ONCE;
+
+extern "C" {
+__declspec(dllimport) int WINAPI InitOnceExecuteOnce(
+ PINIT_ONCE, BOOL(WINAPI*)(PINIT_ONCE, PVOID, PVOID*), void*, void*);
+}
+# endif
+
+namespace __sanitizer {
+template <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..75a1545d00d8b5
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp
@@ -0,0 +1,156 @@
+//===-- sanitizer_win_interception.cpp -------------------- --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific export surface to provide interception for parts of the
+// runtime that are always statically linked, both for overriding user-defined
+// functions as well as registering weak functions that the ASAN runtime should
+// use over defaults.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+# include <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..13db8869abadd5
--- /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..82ef68e0ca70c8
--- /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 a3410261ec8312d4eddb506631c8536dc6a13ee9 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 03/23] 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 18bb35a563167e..89f1215afd0c81 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -929,10 +929,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 998f586cc6d6aa72c513f78ada4db07648d9f067 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 04/23] 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 ca266e3e1d1d3c..7eb38098bed25b 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -201,10 +201,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (TC.getSanitizerArgs(Args).needsAsanRt()) {
CmdArgs.push_back(Args.MakeArgString("-debug"));
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
- if (TC.getSanitizerArgs(Args).needsSharedRt() ||
- Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
- for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
+ CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dynamic"));
+ auto defines = Args.getAllArgValues(options::OPT_D);
+ if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd) ||
+ find(begin(defines), end(defines), "_DLL") != end(defines)) {
// Make sure the dynamic runtime thunk is not optimized out at link time
// to ensure proper SEH handling.
CmdArgs.push_back(Args.MakeArgString(
@@ -213,19 +213,15 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
: "-include:__asan_seh_interceptor"));
// Make sure the linker consider all object files from the dynamic runtime
// thunk.
- CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
+ CmdArgs.push_back(Args.MakeArgString(
+ std::string("-wholearchive:") +
TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
- } else if (DLL) {
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
} else {
- for (const auto &Lib : {"asan", "asan_cxx"}) {
- CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
- // Make sure the linker consider all object files from the static lib.
- // This is necessary because instrumented dlls need access to all the
- // interface exported by the static lib in the main executable.
- CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
- TC.getCompilerRT(Args, Lib)));
- }
+ // Make sure the linker consider all object files from the static runtime
+ // thunk.
+ CmdArgs.push_back(Args.MakeArgString(
+ std::string("-wholearchive:") +
+ TC.getCompilerRT(Args, "asan_static_runtime_thunk")));
}
}
>From f10eae89dbdb6ba638fc9900feb090c48dc3b3ac 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 05/23] 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.
Co-Authored-By: Amy Wishnousky <amyw at microsoft.com>
---
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 675e9acba9e394a65c57567f806910218274f9ee 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 06/23] 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.
Co-authored-by: Amy Wishnousky <amyw at microsoft.com>
---
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 95a96da1db11890fbf4df87034deb39dc9f2045c 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 07/23] 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 869bd5bf0b9422e6918fabdade6b640b8dbd3ba7 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 08/23] 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 e3cf86e21dae2e6bd62ff7f351f160350e4348af 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 09/23] 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 439bf821273871..41c3888275a0f2 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -207,7 +207,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 b7dca2845333b63d20fd71fe14179649bcda5af1 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 10/23] 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
>From 1d9725472c730fe3b56aa0fd9ad51d5a5f630e27 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Fri, 16 Feb 2024 15:43:13 -0800
Subject: [PATCH 11/23] correct asan library checks in clang driver tests.
---
clang/test/Driver/cl-link.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/clang/test/Driver/cl-link.c b/clang/test/Driver/cl-link.c
index ffd0b5ac4bade8..f5260442760452 100644
--- a/clang/test/Driver/cl-link.c
+++ b/clang/test/Driver/cl-link.c
@@ -13,10 +13,8 @@
// ASAN: link.exe
// ASAN: "-debug"
// ASAN: "-incremental:no"
-// ASAN: "{{[^"]*}}clang_rt.asan.lib"
-// ASAN: "-wholearchive:{{.*}}clang_rt.asan.lib"
-// ASAN: "{{[^"]*}}clang_rt.asan_cxx.lib"
-// ASAN: "-wholearchive:{{.*}}clang_rt.asan_cxx.lib"
+// ASAN: "{{[^"]*}}clang_rt.asan_dynamic.lib"
+// ASAN: "-wholearchive:{{.*}}clang_rt.asan_static_runtime_thunk.lib"
// ASAN: "{{.*}}cl-link{{.*}}.obj"
// RUN: %clang_cl -m32 -arch:IA32 --target=i386-pc-win32 /MD /Tc%s -fuse-ld=link -### -fsanitize=address 2>&1 | FileCheck --check-prefix=ASAN-MD %s
@@ -24,7 +22,6 @@
// ASAN-MD: "-debug"
// ASAN-MD: "-incremental:no"
// ASAN-MD: "{{.*}}clang_rt.asan_dynamic.lib"
-// ASAN-MD: "{{[^"]*}}clang_rt.asan_dynamic_runtime_thunk.lib"
// ASAN-MD: "-include:___asan_seh_interceptor"
// ASAN-MD: "-wholearchive:{{.*}}clang_rt.asan_dynamic_runtime_thunk.lib"
// ASAN-MD: "{{.*}}cl-link{{.*}}.obj"
@@ -40,7 +37,8 @@
// ASAN-DLL: "-dll"
// ASAN-DLL: "-debug"
// ASAN-DLL: "-incremental:no"
-// ASAN-DLL: "{{.*}}clang_rt.asan_dll_thunk.lib"
+// ASAN-DLL: "{{.*}}clang_rt.asan_dynamic.lib"
+// ASAN-DLL: "-wholearchive:{{.*}}clang_rt.asan_static_runtime_thunk.lib"
// ASAN-DLL: "{{.*}}cl-link{{.*}}.obj"
// RUN: %clang_cl /Zi /Tc%s -fuse-ld=link -### 2>&1 | FileCheck --check-prefix=DEBUG %s
>From f35df51dc3a841e9a9366f099b2e9bd2ca8f854b Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Tue, 20 Feb 2024 15:44:51 -0800
Subject: [PATCH 12/23] remove unused files from asan windows build
---
.../sanitizer_win_dll_thunk.cpp | 101 ------------------
.../sanitizer_win_runtime_thunk.cpp | 26 -----
2 files changed, 127 deletions(-)
delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp
delete mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp
deleted file mode 100644
index 1562c161a76260..00000000000000
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win_dll_thunk.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-//===-- sanitizer_win_dll_thunk.cpp ---------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// This file defines a family of thunks that should be statically linked into
-// the DLLs that have instrumentation in order to delegate the calls to the
-// shared runtime that lives in the main binary.
-// See https://github.com/google/sanitizers/issues/209 for the details.
-//===----------------------------------------------------------------------===//
-
-#ifdef SANITIZER_DLL_THUNK
-#include "sanitizer_win_defs.h"
-#include "sanitizer_win_dll_thunk.h"
-#include "interception/interception.h"
-
-extern "C" {
-void *WINAPI GetModuleHandleA(const char *module_name);
-void abort();
-}
-
-namespace __sanitizer {
-uptr dllThunkGetRealAddrOrDie(const char *name) {
- uptr ret =
- __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
- if (!ret)
- abort();
- return ret;
-}
-
-int dllThunkIntercept(const char* main_function, uptr dll_function) {
- uptr wrapper = dllThunkGetRealAddrOrDie(main_function);
- if (!__interception::OverrideFunction(dll_function, wrapper, 0))
- abort();
- return 0;
-}
-
-int dllThunkInterceptWhenPossible(const char* main_function,
- const char* default_function, uptr dll_function) {
- uptr wrapper = __interception::InternalGetProcAddress(
- (void *)GetModuleHandleA(0), main_function);
- if (!wrapper)
- wrapper = dllThunkGetRealAddrOrDie(default_function);
- if (!__interception::OverrideFunction(dll_function, wrapper, 0))
- abort();
- return 0;
-}
-} // namespace __sanitizer
-
-// Include Sanitizer Common interface.
-#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "sanitizer_common_interface.inc"
-
-#pragma section(".DLLTH$A", read)
-#pragma section(".DLLTH$Z", read)
-
-typedef void (*DllThunkCB)();
-extern "C" {
-__declspec(allocate(".DLLTH$A")) DllThunkCB __start_dll_thunk;
-__declspec(allocate(".DLLTH$Z")) DllThunkCB __stop_dll_thunk;
-}
-
-// Disable compiler warnings that show up if we declare our own version
-// of a compiler intrinsic (e.g. strlen).
-#pragma warning(disable: 4391)
-#pragma warning(disable: 4392)
-
-extern "C" int __dll_thunk_init() {
- static bool flag = false;
- // __dll_thunk_init is expected to be called by only one thread.
- if (flag) return 0;
- flag = true;
-
- for (DllThunkCB *it = &__start_dll_thunk; it < &__stop_dll_thunk; ++it)
- if (*it)
- (*it)();
-
- // In DLLs, the callbacks are expected to return 0,
- // otherwise CRT initialization fails.
- return 0;
-}
-
-// We want to call dll_thunk_init before C/C++ initializers / constructors are
-// executed, otherwise functions like memset might be invoked.
-#pragma section(".CRT$XIB", long, read)
-__declspec(allocate(".CRT$XIB")) int (*__dll_thunk_preinit)() =
- __dll_thunk_init;
-
-static void WINAPI dll_thunk_thread_init(void *mod, unsigned long reason,
- void *reserved) {
- if (reason == /*DLL_PROCESS_ATTACH=*/1) __dll_thunk_init();
-}
-
-#pragma section(".CRT$XLAB", long, read)
-__declspec(allocate(".CRT$XLAB")) void (WINAPI *__dll_thunk_tls_init)(void *,
- unsigned long, void *) = dll_thunk_thread_init;
-
-#endif // SANITIZER_DLL_THUNK
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp
deleted file mode 100644
index ab2aa594c087bf..00000000000000
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win_runtime_thunk.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-//===-- santizer_win_dynamic_runtime_thunk.cpp ----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines things that need to be present in the application modules
-// to interact with Sanitizer Common, when it is included in a dll.
-//
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
-# define SANITIZER_IMPORT_INTERFACE 1
-# include "sanitizer_win_defs.h"
-// Define weak alias for all weak functions imported from sanitizer common.
-# define INTERFACE_FUNCTION(Name)
-# define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
-# include "sanitizer_common_interface.inc"
-#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
-
-namespace __sanitizer {
-// Add one, otherwise unused, external symbol to this object file so that the
-// Visual C++ linker includes it and reads the .drective section.
-void ForceWholeArchiveIncludeForSanitizerCommon() {}
-} // namespace __sanitizer
>From 6d72c92fb14028d1240590439c7139c493c54aa3 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Tue, 20 Feb 2024 15:45:32 -0800
Subject: [PATCH 13/23] Clean up wording of comment in compiler-rt cmakelists
file
---
compiler-rt/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt
index 8e5a838779f67f..a15c88119dd1ab 100644
--- a/compiler-rt/CMakeLists.txt
+++ b/compiler-rt/CMakeLists.txt
@@ -383,7 +383,7 @@ endif()
if(MSVC)
# 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
+ # 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)
>From 30e4174ab0b280784c3c0079884d924a7fd3034e Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 26 Feb 2024 11:21:53 -0800
Subject: [PATCH 14/23] rename sanitizer_win_thunk_interception.h header guard
---
.../lib/sanitizer_common/sanitizer_win_thunk_interception.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
index 82ef68e0ca70c8..61e3521ba98364 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
@@ -9,8 +9,8 @@
// shared runtime that lives in the sanitizer DLL.
//===----------------------------------------------------------------------===//
-#ifndef SANITIZER_WIN_STATIC_RUNTIME_THUNK_H
-#define SANITIZER_WIN_STATIC_RUNTIME_THUNK_H
+#ifndef SANITIZER_WIN_THUNK_INTERCEPTION_H
+#define SANITIZER_WIN_THUNK_INTERCEPTION_H
#include <stdint.h>
#include "sanitizer_internal_defs.h"
>From 05d982b6a905e0820685de4c16b1d142b648419c Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 18 Mar 2024 10:21:56 -0700
Subject: [PATCH 15/23] Test fixups requiring functional changes
These test changes are seperated from the test changes in
0360f3218a13666123849f6699216bdbebe64833 because they require
various functional changes to asan.
This reverts commit f54e0b4dbf12a155350c53193a42115ec9210587.
---
.../test/asan/TestCases/Windows/free_hook_realloc.cpp | 3 ---
compiler-rt/test/asan/TestCases/Windows/msvc/dll_and_lib.cpp | 5 ++---
.../test/asan/TestCases/Windows/msvc/dll_large_function.cpp | 3 +--
compiler-rt/test/asan/TestCases/Windows/unsymbolized.cpp | 2 +-
compiler-rt/test/asan/TestCases/debug_double_free.cpp | 3 ---
compiler-rt/test/asan/TestCases/debug_report.cpp | 3 ---
compiler-rt/test/asan/TestCases/default_options.cpp | 4 ----
compiler-rt/test/asan/TestCases/on_error_callback.cpp | 3 ---
compiler-rt/test/asan/TestCases/report_error_summary.cpp | 3 ---
9 files changed, 4 insertions(+), 25 deletions(-)
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/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/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/debug_double_free.cpp b/compiler-rt/test/asan/TestCases/debug_double_free.cpp
index d7c59f8b412365..c1cc383b3c1e3f 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 MS CRTs, it comes out all upper case. Use %08x to get
// lowercase hex.
#ifdef _WIN32
diff --git a/compiler-rt/test/asan/TestCases/debug_report.cpp b/compiler-rt/test/asan/TestCases/debug_report.cpp
index d02ce503122265..0dbb9f2fb9988f 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/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/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+
>From 0b749a214aefff96c148e186d6ca162c7d2ada92 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Tue, 19 Mar 2024 10:26:22 -0700
Subject: [PATCH 16/23] Add the compiler-rt libdir to path for lit in both
static and dynamic config
After the windows static runtime is removed these static=static CRT and dynamic=dynamic CRT, both using the dynamic asan runtime.
---
compiler-rt/test/asan/lit.cfg.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py
index 4e4233a6534ff4..05ed7e8dd294e3 100644
--- a/compiler-rt/test/asan/lit.cfg.py
+++ b/compiler-rt/test/asan/lit.cfg.py
@@ -281,7 +281,7 @@ def build_invocation(compile_flags, with_lto=False):
# Add the RT libdir to PATH directly so that we can successfully run the gtest
# binary to list its tests.
-if config.host_os == "Windows" and config.asan_dynamic:
+if config.host_os == "Windows":
os.environ["PATH"] = os.path.pathsep.join(
[config.compiler_rt_libdir, os.environ.get("PATH", "")]
)
>From 6b1c6226158a43ae14252b66068274d9f3eac514 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 1 Apr 2024 16:19:49 -0700
Subject: [PATCH 17/23] Pass -D_DLL and -D_MT to the linker for tests
This is required because now that there's only one asan runtime dll
the dynamic/static CRT wholearchived runtime thunk "flavor"
is determined by passing the /MD or /MDd options, or defining -D_DLL.
---
compiler-rt/lib/asan/tests/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt
index b489bb99aeff3a..7bed4989f6e001 100644
--- a/compiler-rt/lib/asan/tests/CMakeLists.txt
+++ b/compiler-rt/lib/asan/tests/CMakeLists.txt
@@ -203,7 +203,7 @@ function(add_asan_tests arch test_runtime)
CFLAGS ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -D_MT -D_DLL
SOURCES ${ASAN_INST_TEST_SOURCES}
LINK_FLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS}
- -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames
+ -D_MT -D_DLL -Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames
)
else()
set(DYNAMIC_LINK_FLAGS)
>From 8607602374865ddaf7930b2a9b931db7bc482333 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 1 Apr 2024 18:01:03 -0700
Subject: [PATCH 18/23] clang-format
---
.../lib/sanitizer_common/sanitizer_win_thunk_interception.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
index 61e3521ba98364..70177d68aa8e65 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
@@ -66,8 +66,8 @@ void initialize_thunks(const sanitizer_thunk *begin,
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)) { \
+ 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)); \
>From ed8221cf4de88e07d11e27c02bbb60b236fbc190 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Wed, 29 May 2024 14:22:55 -0700
Subject: [PATCH 19/23] [asan][windows] Yet more relaxation of tests
---
compiler-rt/test/asan/TestCases/Windows/double_free.cpp | 6 +++---
compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp | 2 +-
.../test/asan/TestCases/Windows/malloc_right_oob.cpp | 2 +-
compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp | 4 ++--
.../test/asan/TestCases/Windows/realloc_left_oob.cpp | 2 +-
.../test/asan/TestCases/Windows/realloc_right_oob.cpp | 2 +-
compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp | 4 ++--
compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp | 2 +-
.../test/asan/TestCases/Windows/use_after_realloc.cpp | 4 ++--
9 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/compiler-rt/test/asan/TestCases/Windows/double_free.cpp b/compiler-rt/test/asan/TestCases/Windows/double_free.cpp
index e288b40fac47a3..71c45e7e889a22 100644
--- a/compiler-rt/test/asan/TestCases/Windows/double_free.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/double_free.cpp
@@ -9,13 +9,13 @@ int main() {
free(x);
// CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]]
// CHECK-NEXT: {{#0 .* free }}
- // CHECK: {{ #[1-2] .* main .*double_free.cpp}}:[[@LINE-3]]
+ // CHECK: {{ #[1-3] .* main .*double_free.cpp}}:[[@LINE-3]]
// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region
// CHECK-LABEL: freed by thread T0 here:
// CHECK-NEXT: {{#0 .* free }}
- // CHECK: {{ #[1-2] .* main .*double_free.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*double_free.cpp}}:[[@LINE-8]]
// CHECK-LABEL: previously allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* malloc }}
- // CHECK: {{ #[1-2] .* main .*double_free.cpp}}:[[@LINE-12]]
+ // CHECK: {{ #[1-3] .* main .*double_free.cpp}}:[[@LINE-12]]
return 0;
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp
index 7ea95d2b2184a0..e5de2269ffee04 100644
--- a/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/malloc_left_oob.cpp
@@ -12,6 +12,6 @@ int main() {
// CHECK: [[ADDR]] is located 1 bytes before 42-byte region
// CHECK: allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* malloc }}
- // CHECK: {{ #[1-2] .* main .*malloc_left_oob.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*malloc_left_oob.cpp}}:[[@LINE-8]]
free(buffer);
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp
index 1495632456e081..6007345755d88e 100644
--- a/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/malloc_right_oob.cpp
@@ -12,6 +12,6 @@ int main() {
// CHECK: [[ADDR]] is located 0 bytes after 42-byte region
// CHECK: allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* malloc }}
- // CHECK: {{ #[1-2] .* main .*malloc_right_oob.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*malloc_right_oob.cpp}}:[[@LINE-8]]
free(buffer);
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp b/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp
index d1eac7e55f6010..59a944c75b60db 100644
--- a/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/malloc_uaf.cpp
@@ -13,8 +13,8 @@ int main() {
// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
// CHECK: freed by thread T0 here:
// CHECK-NEXT: {{#0 .* free }}
- // CHECK: {{ #[1-2] .* main .*malloc_uaf.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*malloc_uaf.cpp}}:[[@LINE-8]]
// CHECK: previously allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* malloc }}
- // CHECK: {{ #[1-2] .* main .*malloc_uaf.cpp}}:[[@LINE-12]]
+ // CHECK: {{ #[1-3] .* main .*malloc_uaf.cpp}}:[[@LINE-12]]
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp
index ebde5f159ae383..f1fd139c582511 100644
--- a/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/realloc_left_oob.cpp
@@ -12,6 +12,6 @@ int main() {
// CHECK: [[ADDR]] is located 1 bytes before 42-byte region
// CHECK: allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* realloc }}
- // CHECK: {{ #[1-2] .* main .*realloc_left_oob.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*realloc_left_oob.cpp}}:[[@LINE-8]]
free(buffer);
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp b/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp
index 281efed5d30740..ea674f53def793 100644
--- a/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/realloc_right_oob.cpp
@@ -12,6 +12,6 @@ int main() {
// CHECK: [[ADDR]] is located 0 bytes after 42-byte region
// CHECK: allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* realloc }}
- // CHECK: {{ #[1-2] .* main .*realloc_right_oob.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*realloc_right_oob.cpp}}:[[@LINE-8]]
free(buffer);
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp b/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp
index 6ff2217b11a257..7d9c41ef0f4621 100644
--- a/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/realloc_uaf.cpp
@@ -13,8 +13,8 @@ int main() {
// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
// CHECK: freed by thread T0 here:
// CHECK-NEXT: {{#0 .* free }}
- // CHECK: {{ #[1-2] .* main .*realloc_uaf.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*realloc_uaf.cpp}}:[[@LINE-8]]
// CHECK: previously allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* realloc }}
- // CHECK: {{ #[1-2] .* main .*realloc_uaf.cpp}}:[[@LINE-12]]
+ // CHECK: {{ #[1-3] .* main .*realloc_uaf.cpp}}:[[@LINE-12]]
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp b/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp
index be99c89e7083ef..05437abc07c829 100644
--- a/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/symbols_path.cpp
@@ -17,6 +17,6 @@ int main() {
// CHECK: [[ADDR]] is located 1 bytes before 42-byte region
// CHECK: allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* malloc}}
- // CHECK: {{ #[1-2] .* main .*symbols_path.cpp}}:[[@LINE-8]]
+ // CHECK: {{ #[1-3] .* main .*symbols_path.cpp}}:[[@LINE-8]]
free(buffer);
}
diff --git a/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp b/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp
index 4c32c63c38fa1f..35947b3253857c 100644
--- a/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/use_after_realloc.cpp
@@ -15,9 +15,9 @@ int main() {
// CHECK: [[ADDR]] is located 0 bytes inside of 32-byte region
// CHECK: freed by thread T0 here:
// CHECK-NEXT: {{#0 .* realloc }}
- // CHECK: {{ #[1-2] .* main .*use_after_realloc.cpp}}:[[@LINE-9]]
+ // CHECK: {{ #[1-3] .* main .*use_after_realloc.cpp}}:[[@LINE-9]]
// CHECK: previously allocated by thread T0 here:
// CHECK-NEXT: {{#0 .* realloc }}
- // CHECK: {{ #[1-2] .* main .*use_after_realloc.cpp}}:[[@LINE-14]]
+ // CHECK: {{ #[1-3] .* main .*use_after_realloc.cpp}}:[[@LINE-14]]
free(buffer);
}
>From e8c28074e9bf2db996b73607c1f9baa627be1ff4 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Mon, 4 Mar 2024 14:09:23 -0800
Subject: [PATCH 20/23] [LLVM 19] don't optimize register_weak_<whatever> when
building with msvc
---
.../sanitizer_win_thunk_interception.h | 36 ++++++++++---------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
index 70177d68aa8e65..fa7b18fdc18f6d 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.h
@@ -60,22 +60,26 @@ void initialize_thunks(const sanitizer_thunk *begin,
// ------------------ 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
+#ifdef __clang__
+# define REGISTER_WEAK_OPTNONE __attribute__((optnone))
+#else
+# define REGISTER_WEAK_OPTNONE
+#endif
-#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)() = \
+#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) \
+ REGISTER_WEAK_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
>From 4f72a1e96e7e5aef936452edbb943d403152aebc Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Tue, 30 Jul 2024 15:09:20 -0700
Subject: [PATCH 21/23] ensure the asan runtime is always linked with
/OPT:NOICF on windows, which is requried for weak exports to function
correctly
---
compiler-rt/lib/asan/CMakeLists.txt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt
index f992419c6d9822..58e844993f6509 100644
--- a/compiler-rt/lib/asan/CMakeLists.txt
+++ b/compiler-rt/lib/asan/CMakeLists.txt
@@ -131,7 +131,11 @@ append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS)
set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS})
append_list_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC
-ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS)
-append_list_if(MSVC /DEBUG ASAN_DYNAMIC_LINK_FLAGS)
+
+# LLVM turns /OPT:ICF back on when LLVM_ENABLE_PDBs is set
+# we _REALLY_ need to turn it back off for ASAN, because the way
+# asan emulates weak functions from DLLs requires NOICF
+append_list_if(MSVC "/DEBUG;/OPT:NOICF" ASAN_DYNAMIC_LINK_FLAGS)
set(ASAN_DYNAMIC_LIBS
${COMPILER_RT_UNWINDER_LINK_LIBS}
>From 75239e2d3c66c1a2521e154392498ae45abad350 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Tue, 30 Jul 2024 15:10:07 -0700
Subject: [PATCH 22/23] delete asan_win_weak_interception, which was unused
---
.../lib/asan/asan_win_weak_interception.cpp | 22 -------------------
1 file changed, 22 deletions(-)
delete mode 100644 compiler-rt/lib/asan/asan_win_weak_interception.cpp
diff --git a/compiler-rt/lib/asan/asan_win_weak_interception.cpp b/compiler-rt/lib/asan/asan_win_weak_interception.cpp
deleted file mode 100644
index 62534e12e2a69c..00000000000000
--- a/compiler-rt/lib/asan/asan_win_weak_interception.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//===-- asan_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 Address 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.
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC
-#include "sanitizer_common/sanitizer_win_weak_interception.h"
-#include "asan_interface_internal.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 "asan_interface.inc"
-#endif // SANITIZER_DYNAMIC
>From 3667ecd4735b1309efd0d644409673f906d1bdb1 Mon Sep 17 00:00:00 2001
From: Charlie Barto <chbarto at microsoft.com>
Date: Fri, 6 Sep 2024 11:00:30 -0700
Subject: [PATCH 23/23] set the C runtime linkage to /MD only for
sanitizer_common, interception, and asan. Keep the other sanitizers as /MT
since they don't support OneDLL
---
compiler-rt/CMakeLists.txt | 6 +-----
compiler-rt/lib/asan/CMakeLists.txt | 8 +++++++-
compiler-rt/lib/asan/tests/CMakeLists.txt | 1 +
compiler-rt/lib/interception/CMakeLists.txt | 8 ++++++++
compiler-rt/lib/sanitizer_common/CMakeLists.txt | 8 ++++++++
5 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt
index a15c88119dd1ab..deb6994f481854 100644
--- a/compiler-rt/CMakeLists.txt
+++ b/compiler-rt/CMakeLists.txt
@@ -382,11 +382,7 @@ endif()
if(MSVC)
- # 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)
+ set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
# Remove any /M[DT][d] flags, and strip any definitions of _DEBUG.
# Since we're using CMAKE_MSVC_RUNTIME_LIBRARY (CMP0091 set to NEW),
diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt
index 58e844993f6509..c700fcd74edc05 100644
--- a/compiler-rt/lib/asan/CMakeLists.txt
+++ b/compiler-rt/lib/asan/CMakeLists.txt
@@ -97,7 +97,13 @@ SET(ASAN_HEADERS
)
include_directories(..)
-
+if(MSVC)
+ # 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)
+endif()
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_list_if(MSVC /Zl ASAN_CFLAGS)
diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt
index 7bed4989f6e001..0c4b0361ec4936 100644
--- a/compiler-rt/lib/asan/tests/CMakeLists.txt
+++ b/compiler-rt/lib/asan/tests/CMakeLists.txt
@@ -104,6 +104,7 @@ set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINK_FLAGS
set(ASAN_UNITTEST_INSTRUMENTED_LIBS)
set(ASAN_UNITTEST_NOINST_LINK_FLAGS ${ASAN_UNITTEST_COMMON_LINK_FLAGS})
+append_list_if(MSVC -Wl,-nodefaultlib:msvcrt ASAN_UNITTEST_NOINST_LINK_FLAGS)
if(NOT APPLE)
append_list_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINK_FLAGS)
append_list_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINK_FLAGS)
diff --git a/compiler-rt/lib/interception/CMakeLists.txt b/compiler-rt/lib/interception/CMakeLists.txt
index abe9229340be7a..fe7fa27fbc78be 100644
--- a/compiler-rt/lib/interception/CMakeLists.txt
+++ b/compiler-rt/lib/interception/CMakeLists.txt
@@ -14,6 +14,14 @@ set(INTERCEPTION_HEADERS
interception_win.h
)
+if(MSVC)
+ # 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)
+endif()
+
include_directories(..)
set(INTERCEPTION_CFLAGS ${SANITIZER_COMMON_CFLAGS})
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 41c3888275a0f2..556a64f3017488 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -211,6 +211,14 @@ set(SANITIZER_IMPL_HEADERS
sanitizer_win_thunk_interception.h
)
+if(MSVC)
+ # 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)
+endif()
+
include_directories(..)
set(SANITIZER_COMMON_DEFINITIONS
More information about the cfe-commits
mailing list