mirror of
https://github.com/intel/llvm.git
synced 2026-01-20 19:07:53 +08:00
Reland [asan][windows] Eliminate the static asan runtime on windows (#107899)
This reapplies 8fa66c6ca7 ([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 <amyw@microsoft.com>
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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}
|
||||
@@ -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})
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -324,36 +340,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 +353,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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) {
|
||||
__declspec(noinline) void *_malloc_base(size_t size) { return malloc(size); }
|
||||
|
||||
__declspec(noinline) void *_malloc_dbg(size_t size, int, const char *, int) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
ALLOCATION_FUNCTION_ATTRIBUTE
|
||||
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
|
||||
|
||||
|
||||
229
compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
Normal file
229
compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
Normal file
@@ -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
|
||||
112
compiler-rt/lib/asan/asan_win_common_runtime_thunk.cpp
Normal file
112
compiler-rt/lib/asan/asan_win_common_runtime_thunk.cpp
Normal file
@@ -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)
|
||||
38
compiler-rt/lib/asan/asan_win_common_runtime_thunk.h
Normal file
38
compiler-rt/lib/asan/asan_win_common_runtime_thunk.h
Normal file
@@ -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)
|
||||
@@ -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
|
||||
@@ -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 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();
|
||||
}
|
||||
|
||||
// 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;
|
||||
extern "C" __declspec(allocate(".CRT$XID")) int (
|
||||
*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
|
||||
WIN_FORCE_LINK(__asan_schedule_unregister_globals)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
|
||||
#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
|
||||
#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
|
||||
|
||||
110
compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
Normal file
110
compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
//===-- 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(atoll);
|
||||
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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -203,7 +204,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)
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -206,10 +207,18 @@ set(SANITIZER_IMPL_HEADERS
|
||||
sanitizer_vector.h
|
||||
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
|
||||
)
|
||||
|
||||
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
|
||||
@@ -301,57 +310,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
|
||||
sanitizer_win_thunk_interception.cpp
|
||||
CFLAGS ${SANITIZER_CFLAGS} ${RUNTIME_THUNK_CFLAGS}
|
||||
DEFS ${SANITIZER_COMMON_DEFINITIONS})
|
||||
|
||||
add_compiler_rt_object_libraries(SanitizerCommonDllThunk
|
||||
add_compiler_rt_object_libraries(SancovRuntimeThunk
|
||||
${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_runtime_thunk.cpp
|
||||
sanitizer_coverage_win_sections.cpp
|
||||
CFLAGS ${SANITIZER_CFLAGS} -DSANITIZER_DLL_THUNK
|
||||
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
|
||||
${SANITIZER_COMMON_SUPPORTED_OS}
|
||||
ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH}
|
||||
SOURCES
|
||||
sanitizer_coverage_win_dynamic_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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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() {}
|
||||
}
|
||||
71
compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h
Normal file
71
compiler-rt/lib/sanitizer_common/sanitizer_win_immortalize.h
Normal file
@@ -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
|
||||
156
compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp
Normal file
156
compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp
Normal file
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -0,0 +1,85 @@
|
||||
//===-- 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_THUNK_INTERCEPTION_H
|
||||
#define SANITIZER_WIN_THUNK_INTERCEPTION_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
|
||||
#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) \
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]]
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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+
|
||||
|
||||
@@ -130,6 +130,11 @@ if config.asan_dynamic:
|
||||
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 @@ if platform.system() == "Windows":
|
||||
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
|
||||
@@ -262,7 +281,7 @@ if (
|
||||
|
||||
# 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", "")]
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user