Skip to content

Commit 481e9b3

Browse files
barcharcrazCharlie Barto
andauthored
[asan][win][msvc] override new and delete and seperate TUs (#68754)
Migrated from: https://reviews.llvm.org/D155879, with some of the suggestions applied. PR Description copied from above: Currently asan simply exports each overridden new/delete function from the DLL, this works fine normally, but fails if the user is overriding some, but not all, of these functions. In this case the non-overridden functions still come from the asan DLL, but they can't correctly call the user provided override (for example sized op delete should fall back to scalar op delete, if a scalar op delete is provided). Things were also broken in the static build because all the asan overrides were exported from the same TU, and so if you overrode one but not all of them then you'd get ODR violations. This PR should fix both of these cases, but the static case isn't really tested (and indeed one such test does fail) because linking asan statically basically doesn't work on windows right now with LLVM's version of asan. In fact, while we did fix this in our fork, it was a huge mess and we've now made the dynamic version work in all situations (/MD, /MT, /MDd, /MTd, etc) instead. The following is the description from the internal PR that implemented most of this feature. > Previously, operator new/delete were provided as DLL exports when linking dynamically and wholearchived when linked statically. Both scenarios were broken. When linking statically, the user could not define their own op new/delete, because they were already brought into the link by ASAN. When dynamically linking, if the user provided some but not all of the overloads, new and delete would be partially hooked. For example, if the user defined scalar op delete, but the program then called sized op delete, the sized op delete would still be the version provided by ASAN instead of falling back to the user-defined scalar op delete, like the standard requires. > The change <internal PR number>: ASAN operator new/delete fallbacks in the ASAN libraries fixes this moving all operator new/delete definitions to be statically linked. However, this still won't work if /InferAsanLibs still whole-archives everything since then all the op new/deletes would always be provided by ASAN, which is why these changes are necessary. > With these changes, we will no longer wholearchive all of ASAN and will leave the c++ parts (the op new/delete definitions) to be included as a default library. However, it is also necessary to ensure that the asan library with op new/delete will be searched before the corresponding CRT library with the same op new/delete definitions. To accomplish this, we make sure to add the asan library to the beginning of the default lib list, or move it explicitly to the front if it's already in the list. If the C runtime library is explicitly provided, we make sure to warn the user if the current linker line will result in operator new/delete not being provided by ASAN. Note that the rearrangement of defaultlibs is not in this diff. --------- Co-authored-by: Charlie Barto <[email protected]>
1 parent 91b2559 commit 481e9b3

File tree

46 files changed

+1696
-75
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1696
-75
lines changed

compiler-rt/lib/asan/CMakeLists.txt

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,40 @@ if (NOT WIN32 AND NOT APPLE)
3838
)
3939
endif()
4040

41-
set(ASAN_CXX_SOURCES
42-
asan_new_delete.cpp
43-
)
41+
if (WIN32)
42+
set(ASAN_CXX_SOURCES asan_win_new_delete.cpp)
43+
else()
44+
set(ASAN_CXX_SOURCES asan_new_delete.cpp)
45+
endif()
46+
47+
if (APPLE)
48+
set(ASAN_SOURCES ASAN_CXX_SOURCES)
49+
endif()
50+
51+
if (WIN32)
52+
set(ASAN_STATIC_IMPLIB_SOURCES
53+
asan_win_delete_array_thunk.cpp
54+
asan_win_delete_array_align_thunk.cpp
55+
asan_win_delete_array_align_nothrow_thunk.cpp
56+
asan_win_delete_array_nothrow_thunk.cpp
57+
asan_win_delete_array_size_thunk.cpp
58+
asan_win_delete_array_size_align_thunk.cpp
59+
asan_win_delete_scalar_thunk.cpp
60+
asan_win_delete_scalar_align_thunk.cpp
61+
asan_win_delete_scalar_align_nothrow_thunk.cpp
62+
asan_win_delete_scalar_nothrow_thunk.cpp
63+
asan_win_delete_scalar_size_thunk.cpp
64+
asan_win_delete_scalar_size_align_thunk.cpp
65+
asan_win_new_array_thunk.cpp
66+
asan_win_new_array_align_thunk.cpp
67+
asan_win_new_array_align_nothrow_thunk.cpp
68+
asan_win_new_array_nothrow_thunk.cpp
69+
asan_win_new_scalar_thunk.cpp
70+
asan_win_new_scalar_align_thunk.cpp
71+
asan_win_new_scalar_align_nothrow_thunk.cpp
72+
asan_win_new_scalar_nothrow_thunk.cpp
73+
)
74+
endif()
4475

4576
set(ASAN_STATIC_SOURCES
4677
asan_rtl_static.cpp
@@ -83,12 +114,20 @@ SET(ASAN_HEADERS
83114
asan_thread.h
84115
)
85116

117+
if (WIN32)
118+
list(APPEND ASAN_HEADERS
119+
asan_win_new_delete_thunk_common.h
120+
asan_win_thunk_common.h
121+
)
122+
endif()
123+
86124
include_directories(..)
87125

88126
set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
89127
set(ASAN_COMMON_DEFINITIONS ${COMPILER_RT_ASAN_SHADOW_SCALE_DEFINITION})
90128

91129
append_rtti_flag(OFF ASAN_CFLAGS)
130+
append_list_if(MSVC /EHsc ASAN_CFLAGS)
92131

93132
# Silence warnings in system headers with MSVC.
94133
if(NOT CLANG_CL)
@@ -139,6 +178,15 @@ add_compiler_rt_object_libraries(RTAsan_dynamic
139178
CFLAGS ${ASAN_DYNAMIC_CFLAGS}
140179
DEFS ${ASAN_DYNAMIC_DEFINITIONS})
141180

181+
if (WIN32)
182+
add_compiler_rt_object_libraries(RTAsan_static_implib
183+
ARCHS ${ASAN_SUPPORTED_ARCH}
184+
SOURCES ${ASAN_STATIC_IMPLIB_SOURCES}
185+
ADDITIONAL_HEADERS ${ASAN_HEADERS}
186+
CFLAGS ${ASAN_CFLAGS} ${NO_DEFAULT_LIBS_OPTION}
187+
DEFS ${ASAN_COMMON_DEFINITIONS})
188+
endif()
189+
142190
if(NOT APPLE)
143191
add_compiler_rt_object_libraries(RTAsan
144192
ARCHS ${ASAN_SUPPORTED_ARCH}
@@ -239,13 +287,24 @@ else()
239287
DEFS ${ASAN_COMMON_DEFINITIONS}
240288
PARENT_TARGET asan)
241289

290+
if(WIN32)
242291
add_compiler_rt_runtime(clang_rt.asan_static
243292
STATIC
244293
ARCHS ${ASAN_SUPPORTED_ARCH}
245294
OBJECT_LIBS RTAsan_static
295+
RTAsan_static_implib
246296
CFLAGS ${ASAN_CFLAGS}
247297
DEFS ${ASAN_COMMON_DEFINITIONS}
248298
PARENT_TARGET asan)
299+
else()
300+
add_compiler_rt_runtime(clang_rt.asan_static
301+
STATIC
302+
ARCHS ${ASAN_SUPPORTED_ARCH}
303+
OBJECT_LIBS RTAsan_static
304+
CFLAGS ${ASAN_CFLAGS}
305+
DEFS ${ASAN_COMMON_DEFINITIONS}
306+
PARENT_TARGET asan)
307+
endif()
249308

250309
add_compiler_rt_runtime(clang_rt.asan-preinit
251310
STATIC
@@ -255,6 +314,13 @@ else()
255314
DEFS ${ASAN_COMMON_DEFINITIONS}
256315
PARENT_TARGET asan)
257316

317+
318+
if (MSVC AND COMPILER_RT_DEBUG)
319+
set(MSVC_DBG_SUFFIX _dbg)
320+
else()
321+
set(MSVC_DBG_SUFFIX )
322+
endif()
323+
258324
foreach(arch ${ASAN_SUPPORTED_ARCH})
259325
if (COMPILER_RT_HAS_VERSION_SCRIPT)
260326
add_sanitizer_rt_version_list(clang_rt.asan-dynamic-${arch}
@@ -311,6 +377,27 @@ else()
311377
DEFS ${ASAN_DYNAMIC_DEFINITIONS}
312378
PARENT_TARGET asan)
313379

380+
if(WIN32)
381+
set_target_properties(clang_rt.asan${MSVC_DBG_SUFFIX}-dynamic-${arch}
382+
PROPERTIES ARCHIVE_OUTPUT_NAME clang_rt.asan_dynamic-${arch}_implib
383+
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
384+
385+
add_library(clang_rt.asan-${arch}_implib STATIC)
386+
target_link_libraries(clang_rt.asan-${arch}_implib RTAsan_static_implib.${arch})
387+
add_dependencies(asan clang_rt.asan-${arch}_implib)
388+
add_dependencies(clang_rt.asan-${arch}_implib clang_rt.asan${MSVC_DBG_SUFFIX}-dynamic-${arch})
389+
get_compiler_rt_output_dir(${arch} IMPLIB_OUTPUT_DIR)
390+
set_target_properties(clang_rt.asan-${arch}_implib
391+
PROPERTIES ARCHIVE_OUTPUT_NAME clang_rt.asan${MSVC_DBG_SUFFIX}_dynamic-${arch}
392+
ARCHIVE_OUTPUT_DIRECTORY ${IMPLIB_OUTPUT_DIR}
393+
STATIC_LIBRARY_OPTIONS "$<TARGET_LINKER_FILE:clang_rt.asan${MSVC_DBG_SUFFIX}-dynamic-${arch}>")
394+
get_compiler_rt_install_dir(${arch} IMPLIB_INSTALL_DIR)
395+
install(TARGETS clang_rt.asan-${arch}_implib
396+
ARCHIVE DESTINATION ${IMPLIB_INSTALL_DIR}
397+
LIBRARY DESTINATION ${IMPLIB_INSTALL_DIR}
398+
RUNTIME DESTINATION ${IMPLIB_INSTALL_DIR})
399+
endif()
400+
314401
if (SANITIZER_USE_SYMBOLS AND NOT ${arch} STREQUAL "i386")
315402
add_sanitizer_rt_symbols(clang_rt.asan_cxx
316403
ARCHS ${arch})

compiler-rt/lib/asan/asan_interface.inc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,22 @@ INTERFACE_FUNCTION(__asan_update_allocation_context)
187187
INTERFACE_WEAK_FUNCTION(__asan_default_options)
188188
INTERFACE_WEAK_FUNCTION(__asan_default_suppressions)
189189
INTERFACE_WEAK_FUNCTION(__asan_on_error)
190+
191+
#if SANITIZER_WINDOWS
192+
INTERFACE_FUNCTION(__asan_delete)
193+
INTERFACE_FUNCTION(__asan_delete_align)
194+
INTERFACE_FUNCTION(__asan_delete_array)
195+
INTERFACE_FUNCTION(__asan_delete_array_align)
196+
INTERFACE_FUNCTION(__asan_delete_array_size)
197+
INTERFACE_FUNCTION(__asan_delete_array_size_align)
198+
INTERFACE_FUNCTION(__asan_delete_size)
199+
INTERFACE_FUNCTION(__asan_delete_size_align)
200+
INTERFACE_FUNCTION(__asan_new)
201+
INTERFACE_FUNCTION(__asan_new_align)
202+
INTERFACE_FUNCTION(__asan_new_align_nothrow)
203+
INTERFACE_FUNCTION(__asan_new_array)
204+
INTERFACE_FUNCTION(__asan_new_array_align)
205+
INTERFACE_FUNCTION(__asan_new_array_align_nothrow)
206+
INTERFACE_FUNCTION(__asan_new_array_nothrow)
207+
INTERFACE_FUNCTION(__asan_new_nothrow)
208+
#endif // SANITIZER_WINDOWS
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===-- asan_win_delete_array_align_nothrow_thunk.cc ----------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
// Avoid tailcall optimization to preserve stack frame.
19+
#pragma optimize("", off)
20+
void operator delete[](void* ptr, std::align_val_t align,
21+
std::nothrow_t const&) noexcept {
22+
// nothrow version is identical to throwing version
23+
operator delete[](ptr, align);
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===-- asan_win_delete_array_align_thunk.cc ------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
__asan_InitDefine<op_delete_array_align> init_delete_array_align;
19+
20+
// Avoid tailcall optimization to preserve stack frame.
21+
#pragma optimize("", off)
22+
void operator delete[](void* ptr, std::align_val_t align) noexcept {
23+
if (__asan_InitDefine<op_delete_scalar_align>::defined) {
24+
__asan_delete_array_align(ptr, align);
25+
} else {
26+
operator delete(ptr, align);
27+
}
28+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- asan_win_delete_array_nothrow_thunk.cc ----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
// Avoid tailcall optimization to preserve stack frame.
19+
#pragma optimize("", off)
20+
void operator delete[](void* ptr, std::nothrow_t const&) noexcept {
21+
// nothrow version is identical to throwing version
22+
operator delete[](ptr);
23+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===-- asan_win_delete_array_size_align_thunk.cc -------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
// Avoid tailcall optimization to preserve stack frame.
19+
#pragma optimize("", off)
20+
void operator delete[](void* ptr, size_t size,
21+
std::align_val_t align) noexcept {
22+
if (__asan_InitDefine<op_delete_scalar_align>::defined &&
23+
__asan_InitDefine<op_delete_array_align>::defined) {
24+
__asan_delete_array_size_align(ptr, size, align);
25+
} else {
26+
operator delete[](ptr, align);
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===-- asan_win_delete_array_size_thunk.cc -------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
// Avoid tailcall optimization to preserve stack frame.
19+
#pragma optimize("", off)
20+
void operator delete[](void* ptr, size_t size) noexcept {
21+
if (__asan_InitDefine<op_delete_scalar>::defined &&
22+
__asan_InitDefine<op_delete_array>::defined) {
23+
__asan_delete_array_size(ptr, size);
24+
} else {
25+
operator delete[](ptr);
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===-- asan_win_delete_array_thunk.cc ------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
__asan_InitDefine<op_delete_array> init_delete_array;
19+
20+
// Avoid tailcall optimization to preserve stack frame.
21+
#pragma optimize("", off)
22+
void operator delete[](void* ptr) noexcept {
23+
if (__asan_InitDefine<op_delete_scalar>::defined) {
24+
__asan_delete_array(ptr);
25+
} else {
26+
operator delete(ptr);
27+
}
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===-- asan_win_delete_scalar_align_nothrow_thunk.cc ---------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
// Avoid tailcall optimization to preserve stack frame.
19+
#pragma optimize("", off)
20+
void operator delete(void* ptr, std::align_val_t align,
21+
std::nothrow_t const&) noexcept {
22+
// nothrow version is identical to throwing version
23+
operator delete(ptr, align);
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===-- asan_win_delete_scalar_align_thunk.cc -----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of AddressSanitizer, an address sanity checker.
10+
//
11+
// Windows-specific user-provided new/delete operator detection and fallback.
12+
//===----------------------------------------------------------------------===//
13+
#include "asan_win_new_delete_thunk_common.h"
14+
15+
// see diagram in asan_win_new_delete_thunk_common.h for the ordering of the
16+
// new/delete fallbacks.
17+
18+
__asan_InitDefine<op_delete_scalar_align> init_delete_scalar_align;
19+
20+
// Avoid tailcall optimization to preserve stack frame.
21+
#pragma optimize("", off)
22+
void operator delete(void* ptr, std::align_val_t align) noexcept {
23+
__asan_delete_align(ptr, align);
24+
}

0 commit comments

Comments
 (0)