Skip to content

Commit

Permalink
Reland [asan][windows] Eliminate the static asan runtime on windows (#…
Browse files Browse the repository at this point in the history
…107899)

This reapplies 8fa66c6 ([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.

---------

Co-authored-by: Amy Wishnousky <[email protected]>
  • Loading branch information
barcharcraz and amyw-msft authored Sep 9, 2024
1 parent 3403438 commit 53a81d4
Show file tree
Hide file tree
Showing 58 changed files with 1,315 additions and 1,092 deletions.
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}
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

1 comment on commit 53a81d4

@lhames
Copy link
Contributor

@lhames lhames commented on 53a81d4 Sep 12, 2024

Choose a reason for hiding this comment

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

@barcharcraz @amyw-msft -- Several ASan tests began failing on Darwin in https://green.lab.llvm.org/job/llvm.org/job/clang-stage1-RA/2034/ -- could this commit have caused the issues?

Please sign in to comment.