[asan/win] Fix incremental linking vs. global registration

The MSVC incremental linker pads every global out to 256 bytes in case
it changes size after an incremental link. So, skip over null entries in
the DSO-wide asan globals array. This only works if the global padding
size is divisible by the size of the asan global object, so add some
defensive CHECKs.

llvm-svn: 287780
This commit is contained in:
Reid Kleckner 2016-11-23 17:37:00 +00:00
parent 8d0381d61f
commit f174a0bbd2
4 changed files with 17 additions and 7 deletions

View File

@ -64,7 +64,6 @@ 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)
append_list_if(MSVC /INCREMENTAL:NO ASAN_DYNAMIC_LINK_FLAGS)
append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS)

View File

@ -192,7 +192,6 @@ static inline bool UseODRIndicator(const Global *g) {
// This function may be called more than once for every global
// so we store the globals in a map.
static void RegisterGlobal(const Global *g) {
CHECK(g->beg);
CHECK(asan_inited);
if (flags()->report_globals >= 2)
ReportGlobal(*g, "Added");
@ -349,6 +348,20 @@ void __asan_register_globals(__asan_global *globals, uptr n) {
Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
}
for (uptr i = 0; i < n; i++) {
if (SANITIZER_WINDOWS && globals[i].beg == 0) {
// The MSVC incremental linker may pad globals out to 256 bytes. As long
// as __asan_global is less than 256 bytes large and its size is a power
// of two, we can skip over the padding.
static_assert(
sizeof(__asan_global) < 256 &&
(sizeof(__asan_global) & (sizeof(__asan_global) - 1)) == 0,
"sizeof(__asan_global) incompatible with incremental linker padding");
// If these are padding bytes, the rest of the global should be zero.
CHECK(globals[i].size == 0 && globals[i].size_with_redzone == 0 &&
globals[i].name == nullptr && globals[i].module_name == nullptr &&
globals[i].odr_indicator == 0);
continue;
}
RegisterGlobal(&globals[i]);
}
}

View File

@ -19,13 +19,13 @@ namespace __asan {
#pragma section(".ASAN$GA", read, write) // NOLINT
#pragma section(".ASAN$GZ", read, write) // NOLINT
extern "C" __declspec(allocate(".ASAN$GA"))
uptr __asan_globals_start = 0;
__asan_global __asan_globals_start = {};
extern "C" __declspec(allocate(".ASAN$GZ"))
uptr __asan_globals_end = 0;
__asan_global __asan_globals_end = {};
#pragma comment(linker, "/merge:.ASAN=.data")
static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
__asan_global *start = (__asan_global *)(&__asan_globals_start + 1);
__asan_global *start = &__asan_globals_start + 1;
__asan_global *end = (__asan_global *)&__asan_globals_end;
// We know end >= start because the linker sorts the portion after the dollar
// sign alphabetically.

View File

@ -47,8 +47,6 @@ else()
endif()
if(MSVC)
list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -gcodeview)
# Incremental linking appears to break our global registration mechanism.
list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -Wl,-incremental:no)
endif()
list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -g)