Skip to content

Reland [asan][windows] Eliminate the static asan runtime on windows #107899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4c0769c
Build ASAN libraries with /MD instead of /MT on winodws
barcharcraz Feb 13, 2024
d51cbaa
Remove the static ASAN runtimes
barcharcraz Feb 13, 2024
a341026
make it an error to pass -static-libsan on windows and make shared th…
barcharcraz Feb 13, 2024
998f586
Teach the MSVC toolchain driver to link the correct asan libraries.
barcharcraz Feb 13, 2024
f10eae8
Because all DLLs get initialized before the main module
barcharcraz Feb 13, 2024
675e9ac
Clean up asan_malloc_win.cpp and add exports
barcharcraz Feb 13, 2024
95a96da
add new substitutions to the tests to support the new static/dynamic …
barcharcraz Feb 13, 2024
869bd5b
intercept atoll for the static runtime.
barcharcraz Feb 13, 2024
e3cf86e
Remove sanitizer_win_dll_thunk.h from the build
barcharcraz Feb 16, 2024
b7dca28
exclude windows specific interface symbols from linux/darwin tests.
barcharcraz Feb 16, 2024
1d97254
correct asan library checks in clang driver tests.
barcharcraz Feb 16, 2024
f35df51
remove unused files from asan windows build
barcharcraz Feb 20, 2024
6d72c92
Clean up wording of comment in compiler-rt cmakelists file
barcharcraz Feb 20, 2024
30e4174
rename sanitizer_win_thunk_interception.h header guard
barcharcraz Feb 26, 2024
05d982b
Test fixups requiring functional changes
barcharcraz Mar 18, 2024
0b749a2
Add the compiler-rt libdir to path for lit in both static and dynamic…
barcharcraz Mar 19, 2024
6b1c622
Pass -D_DLL and -D_MT to the linker for tests
barcharcraz Apr 1, 2024
8607602
clang-format
barcharcraz Apr 2, 2024
ed8221c
[asan][windows] Yet more relaxation of tests
barcharcraz May 29, 2024
e8c2807
[LLVM 19] don't optimize register_weak_<whatever> when building with …
barcharcraz Mar 4, 2024
4f72a1e
ensure the asan runtime is always linked with /OPT:NOICF on windows, …
barcharcraz Jul 30, 2024
75239e2
delete asan_win_weak_interception, which was unused
barcharcraz Jul 30, 2024
3667ecd
set the C runtime linkage to /MD only for sanitizer_common, intercept…
barcharcraz Sep 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
26 changes: 11 additions & 15 deletions clang/lib/Driver/ToolChains/MSVC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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")));
}
}

Expand Down
10 changes: 4 additions & 6 deletions clang/test/Driver/cl-link.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,15 @@
// 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
// ASAN-MD: link.exe
// 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"
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ 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)

# Remove any /M[DT][d] flags, and strip any definitions of _DEBUG.
Expand Down
173 changes: 94 additions & 79 deletions compiler-rt/lib/asan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -83,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)
Expand Down Expand Up @@ -117,7 +137,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}
Expand All @@ -136,7 +160,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}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line seems to be the problem, reverting it fixes the tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be safe to revert, and I'll make a PR reverting it (and probably just commit it if it doesn't get any reviews before I go to sleep).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened #108329 which should revert this particular edit (which was arguably a driveby change anyway)

ADDITIONAL_HEADERS ${ASAN_HEADERS}
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
DEFS ${ASAN_DYNAMIC_DEFINITIONS})
Expand Down Expand Up @@ -221,46 +245,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)
Expand All @@ -278,25 +308,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.
Expand Down Expand Up @@ -324,49 +340,48 @@ 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})

add_compiler_rt_runtime(clang_rt.asan_dynamic_runtime_thunk
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()
Expand Down
Loading