Index: compiler-rt/cmake/config-ix.cmake =================================================================== --- compiler-rt/cmake/config-ix.cmake +++ compiler-rt/cmake/config-ix.cmake @@ -648,10 +648,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND - OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia|Windows" AND - # TODO: Support builds with MSVC. - NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" AND - NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia|Windows") set(COMPILER_RT_HAS_FUZZER TRUE) else() set(COMPILER_RT_HAS_FUZZER FALSE) Index: compiler-rt/lib/fuzzer/CMakeLists.txt =================================================================== --- compiler-rt/lib/fuzzer/CMakeLists.txt +++ compiler-rt/lib/fuzzer/CMakeLists.txt @@ -71,6 +71,9 @@ if(NOT HAS_THREAD_LOCAL) list(APPEND LIBFUZZER_CFLAGS -Dthread_local=__thread) + if (OS_NAME MATCHES "Windows") + list(APPEND LIBFUZZER_CFLAGS -D_XKEYCHECK_H=1) + endif() endif() set(FUZZER_SUPPORTED_OS ${SANITIZER_COMMON_SUPPORTED_OS}) Index: compiler-rt/lib/fuzzer/FuzzerDefs.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerDefs.h +++ compiler-rt/lib/fuzzer/FuzzerDefs.h @@ -113,7 +113,33 @@ # define ALWAYS_INLINE #endif // __clang__ +#if LIBFUZZER_WINDOWS +#include + +#define ATTRIBUTE_INTERFACE __declspec(dllexport) +// This is used for __sancov_lowest_stack which is needed for +// -fsanitize-coverage=stack-depth. That feature is not yet available on +// Windows, so make the symbol static to avoid linking errors. +#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC static + +#define ATTRIBUTE_NO_SANITIZE_ADDRESS +#define ATTRIBUTE_NOINLINE __declspec(noinline) +#define ATTRIBUTE_VISIBILITY_DEFAULT + +#define ATTRIBUTE_ALIGNED(X) __declspec(align(X)) +#define GET_CALLER_PC() _ReturnAddress() +#else +#define ATTRIBUTE_INTERFACE __attribute__((visibility("default"))) +#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \ + ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local + #define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) +#define ATTRIBUTE_NOINLINE __attribute__((noinline)) +#define ATTRIBUTE_VISIBILITY_DEFAULT __attribute__((visibility("default"))) + +#define ATTRIBUTE_ALIGNED(X) __attribute__((aligned(X))) +#define GET_CALLER_PC() __builtin_return_address(0) +#endif // LIBFUZZER_WINDOWS #if defined(__has_feature) # if __has_feature(address_sanitizer) @@ -127,19 +153,6 @@ # define ATTRIBUTE_NO_SANITIZE_ALL #endif -#if LIBFUZZER_WINDOWS -#define ATTRIBUTE_INTERFACE __declspec(dllexport) -// This is used for __sancov_lowest_stack which is needed for -// -fsanitize-coverage=stack-depth. That feature is not yet available on -// Windows, so make the symbol static to avoid linking errors. -#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \ - __attribute__((tls_model("initial-exec"))) thread_local static -#else -#define ATTRIBUTE_INTERFACE __attribute__((visibility("default"))) -#define ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC \ - ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local -#endif - namespace fuzzer { template T Min(T a, T b) { return a < b ? a : b; } @@ -184,10 +197,38 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); inline uint8_t Bswap(uint8_t x) { return x; } +#if LIBFUZZER_WINDOWS +inline uint16_t Bswap(uint16_t x) { return _byteswap_ushort(x); } +inline uint32_t Bswap(uint32_t x) { return _byteswap_ulong(x); } +inline uint64_t Bswap(uint64_t x) { return _byteswap_uint64(x); } + +// The functions below were mostly copied from +// compiler-rt/lib/builtins/int_lib.h which defines the __builtin functions used +// outside of Windows. +inline uint32_t Clzll(uint64_t X) { + unsigned long LeadZeroIdx = 0; + // Does not work on x86 which is unsupported by LibFuzzer on Windows anyway. + if (_BitScanReverse64(&LeadZeroIdx, X)) return 63 - LeadZeroIdx; + return 64; +} + +inline uint32_t Clz(uint32_t X) { + unsigned long LeadZeroIdx = 0; + if (_BitScanReverse(&LeadZeroIdx, X)) return 31 - LeadZeroIdx; + return 32; +} + +inline int Popcountll(unsigned long long X) { return __popcnt64(X); } +#else inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); } inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); } inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); } +inline uint32_t Clzll(unsigned long long X) { return __builtin_clzll(X); } +inline uint32_t Clz(unsigned long long X) { return __builtin_clz(X); } +inline int Popcountll(unsigned long long X) { return __builtin_popcountll(X); } +#endif // LIBFUZZER_WINDOWS + uint8_t *ExtraCountersBegin(); uint8_t *ExtraCountersEnd(); void ClearExtraCounters(); Index: compiler-rt/lib/fuzzer/FuzzerDriver.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerDriver.cpp +++ compiler-rt/lib/fuzzer/FuzzerDriver.cpp @@ -29,7 +29,12 @@ // This function should be present in the libFuzzer so that the client // binary can test for its existence. +#if LIBFUZZER_WINDOWS +extern "C" void __libfuzzer_is_present() {} +#pragma comment(linker, "/include:__libfuzzer_is_present") +#else extern "C" __attribute__((used)) void __libfuzzer_is_present() {} +#endif // LIBFUZZER_WINDOWS namespace fuzzer { Index: compiler-rt/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp +++ compiler-rt/lib/fuzzer/FuzzerExtFunctionsWeakAlias.cpp @@ -18,12 +18,45 @@ extern "C" { // Declare these symbols as weak to allow them to be optionally defined. -#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ - RETURN_TYPE NAME##Def FUNC_SIG { \ - Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ - exit(1); \ - } \ +// MSVC does not support attributes so we must use the alternatename declspec +// when compiling with MSVC. +// Clang supports alternatename in theory. However, the clang optimizer does not +// know about it and will assume the function is never equal to its +// alternatename. This prevents us from knowing whether a function has actually +// been defined by the user. So instead of using alternatename use the "weak" +// and "alias" attributes (which clang-cl supports) to accomplish this. Define +// EXT_FUNC to do this if we are using clang, otherwise define it to use +// alternatename. +#ifdef __clang__ +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE NAME##Def FUNC_SIG { \ + Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ + exit(1); \ + } \ RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def"))); +#else +// Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h +#if defined(_M_IX86) || defined(__i386__) +#define WIN_SYM_PREFIX "_" +#else +#define WIN_SYM_PREFIX +#endif + +// Intermediate macro to ensure the parameter is expanded before stringified. +#define STRINGIFY_(A) #A +#define STRINGIFY(A) STRINGIFY_(A) + +#define WIN_WEAK_ALIAS(Name, Default) \ + __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \ + Name) "=" WIN_SYM_PREFIX STRINGIFY(Default))) + +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE NAME##Def FUNC_SIG { \ + Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ + exit(1); \ + } \ + WIN_WEAK_ALIAS(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG; +#endif // __clang__ #include "FuzzerExtFunctions.def" Index: compiler-rt/lib/fuzzer/FuzzerInterface.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerInterface.h +++ compiler-rt/lib/fuzzer/FuzzerInterface.h @@ -26,25 +26,32 @@ extern "C" { #endif // __cplusplus +// Define FUZZER_INTERFACE_VISIBILITY to set default visibility in a way that +// doesn't break MSVC. +#if defined(_WIN32) && _WIN32 +#define FUZZER_INTERFACE_VISIBILITY +#else +#define FUZZER_INTERFACE_VISIBILITY __attribute__((visibility("default"))) +#endif + // Mandatory user-provided target function. // Executes the code under test with [Data, Data+Size) as the input. // libFuzzer will invoke this function *many* times with different inputs. // Must return 0. -__attribute__((visibility("default"))) int +FUZZER_INTERFACE_VISIBILITY int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); // Optional user-provided initialization function. // If provided, this function will be called by libFuzzer once at startup. // It may read and modify argc/argv. // Must return 0. -__attribute__((visibility("default"))) int LLVMFuzzerInitialize(int *argc, - char ***argv); +FUZZER_INTERFACE_VISIBILITY int LLVMFuzzerInitialize(int *argc, char ***argv); // Optional user-provided custom mutator. // Mutates raw data in [Data, Data+Size) inplace. // Returns the new size, which is not greater than MaxSize. // Given the same Seed produces the same mutation. -__attribute__((visibility("default"))) size_t +FUZZER_INTERFACE_VISIBILITY size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed); @@ -52,7 +59,7 @@ // Combines pieces of Data1 & Data2 together into Out. // Returns the new size, which is not greater than MaxOutSize. // Should produce the same mutation given the same Seed. -__attribute__((visibility("default"))) size_t +FUZZER_INTERFACE_VISIBILITY size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, uint8_t *Out, size_t MaxOutSize, unsigned int Seed); @@ -61,9 +68,11 @@ // libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator. // Mutates raw data in [Data, Data+Size) inplace. // Returns the new size, which is not greater than MaxSize. -__attribute__((visibility("default"))) size_t +FUZZER_INTERFACE_VISIBILITY size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); +#undef FUZZER_INTERFACE_VISIBILITY + #ifdef __cplusplus } // extern "C" #endif // __cplusplus Index: compiler-rt/lib/fuzzer/FuzzerLoop.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -890,15 +890,15 @@ extern "C" { -__attribute__((visibility("default"))) size_t -LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { +ATTRIBUTE_VISIBILITY_DEFAULT +size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { assert(fuzzer::F); return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); } // Experimental -__attribute__((visibility("default"))) void -LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { +ATTRIBUTE_VISIBILITY_DEFAULT +void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { assert(fuzzer::F); fuzzer::F->AnnounceOutput(Data, Size); } Index: compiler-rt/lib/fuzzer/FuzzerMain.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerMain.cpp +++ compiler-rt/lib/fuzzer/FuzzerMain.cpp @@ -16,6 +16,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); } // extern "C" -__attribute__((visibility("default"))) int main(int argc, char **argv) { +ATTRIBUTE_VISIBILITY_DEFAULT int main(int argc, char **argv) { return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput); } Index: compiler-rt/lib/fuzzer/FuzzerSHA1.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerSHA1.cpp +++ compiler-rt/lib/fuzzer/FuzzerSHA1.cpp @@ -38,7 +38,8 @@ # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define SHA_BIG_ENDIAN # endif -#else // ! defined __LITTLE_ENDIAN__ +// Windows doesn't have . It is always little endian, even on ARM. +#elif !defined(LIBFUZZER_WINDOWS) // ! defined __LITTLE_ENDIAN__ # include // machine/endian.h # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define SHA_BIG_ENDIAN Index: compiler-rt/lib/fuzzer/FuzzerTracePC.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerTracePC.h +++ compiler-rt/lib/fuzzer/FuzzerTracePC.h @@ -249,7 +249,7 @@ template // void Callback(size_t Feature) ATTRIBUTE_NO_SANITIZE_ADDRESS -__attribute__((noinline)) +ATTRIBUTE_NOINLINE void TracePC::CollectFeatures(Callback HandleFeature) const { uint8_t *Counters = this->Counters(); size_t N = GetNumPCs(); Index: compiler-rt/lib/fuzzer/FuzzerTracePC.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerTracePC.cpp +++ compiler-rt/lib/fuzzer/FuzzerTracePC.cpp @@ -446,9 +446,8 @@ TORC4.Insert(ArgXor, Arg1, Arg2); else if (sizeof(T) == 8) TORC8.Insert(ArgXor, Arg1, Arg2); - uint64_t HammingDistance = __builtin_popcountll(ArgXor); // [0,64] - uint64_t AbsoluteDistance = - (Arg1 == Arg2 ? 0 : __builtin_clzll(Arg1 - Arg2) + 1); + uint64_t HammingDistance = Popcountll(ArgXor); // [0,64] + uint64_t AbsoluteDistance = (Arg1 == Arg2 ? 0 : Clzll(Arg1 - Arg2) + 1); ValueProfileMap.AddValue(PC * 128 + HammingDistance); ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); } @@ -491,7 +490,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); uint32_t Idx = *Guard; __sancov_trace_pc_pcs[Idx] = PC; __sancov_trace_pc_guard_8bit_counters[Idx]++; @@ -502,7 +501,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc() { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); uintptr_t Idx = PC & (((uintptr_t)1 << fuzzer::TracePC::kTracePcBits) - 1); __sancov_trace_pc_pcs[Idx] = PC; __sancov_trace_pc_guard_8bit_counters[Idx]++; @@ -527,7 +526,7 @@ ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_ALL void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCallerCallee(PC, Callee); } @@ -535,7 +534,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -546,7 +545,7 @@ // the behaviour of __sanitizer_cov_trace_cmp[1248] ones. This, however, // should be changed later to make full use of instrumentation. void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -554,7 +553,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -562,7 +561,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -570,7 +569,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -578,7 +577,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -586,7 +585,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -594,7 +593,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Arg1, Arg2); } @@ -608,7 +607,7 @@ // Skip the most common and the most boring case. if (Vals[N - 1] < 256 && Val < 256) return; - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); size_t i; uint64_t Token = 0; for (i = 0; i < N; i++) { @@ -629,7 +628,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_div4(uint32_t Val) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Val, (uint32_t)0); } @@ -637,7 +636,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_div8(uint64_t Val) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Val, (uint64_t)0); } @@ -645,7 +644,7 @@ ATTRIBUTE_NO_SANITIZE_ALL ATTRIBUTE_TARGET_POPCNT void __sanitizer_cov_trace_gep(uintptr_t Idx) { - uintptr_t PC = reinterpret_cast(__builtin_return_address(0)); + uintptr_t PC = reinterpret_cast(GET_CALLER_PC()); fuzzer::TPC.HandleCmp(PC, Idx, (uintptr_t)0); } Index: compiler-rt/lib/fuzzer/FuzzerUtil.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerUtil.h +++ compiler-rt/lib/fuzzer/FuzzerUtil.h @@ -84,7 +84,7 @@ size_t SimpleFastHash(const uint8_t *Data, size_t Size); -inline uint32_t Log(uint32_t X) { return 32 - __builtin_clz(X) - 1; } +inline uint32_t Log(uint32_t X) { return 32 - Clz(X) - 1; } } // namespace fuzzer Index: compiler-rt/lib/fuzzer/FuzzerValueBitMap.h =================================================================== --- compiler-rt/lib/fuzzer/FuzzerValueBitMap.h +++ compiler-rt/lib/fuzzer/FuzzerValueBitMap.h @@ -35,7 +35,7 @@ uintptr_t WordIdx = Idx / kBitsInWord; uintptr_t BitIdx = Idx % kBitsInWord; uintptr_t Old = Map[WordIdx]; - uintptr_t New = Old | (1UL << BitIdx); + uintptr_t New = Old | (1ULL << BitIdx); Map[WordIdx] = New; return New != Old; } @@ -49,7 +49,7 @@ assert(Idx < kMapSizeInBits); uintptr_t WordIdx = Idx / kBitsInWord; uintptr_t BitIdx = Idx % kBitsInWord; - return Map[WordIdx] & (1UL << BitIdx); + return Map[WordIdx] & (1ULL << BitIdx); } size_t SizeInBits() const { return kMapSizeInBits; } @@ -65,7 +65,7 @@ } private: - uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512))); + ATTRIBUTE_ALIGNED(512) uintptr_t Map[kMapSizeInWords]; }; } // namespace fuzzer Index: compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_coverage_win_sections.cc @@ -28,35 +28,42 @@ #if SANITIZER_WINDOWS #include extern "C" { -// The Guard array and counter array should both be merged into the .data -// section to reduce the number of PE sections However, because PCTable is -// constant it should be merged with the .rdata section. -#pragma section(".SCOV$GA", read, write) // NOLINT -// Use align(1) to avoid adding any padding that will mess up clients trying to -// determine the start and end of the array. -__declspec(allocate(".SCOV$GA")) __declspec(align(1)) uint64_t - __start___sancov_guards = 0; -#pragma section(".SCOV$GZ", read, write) // NOLINT -__declspec(allocate(".SCOV$GZ")) __declspec(align(1)) uint64_t - __stop___sancov_guards = 0; +// Use align(1) to avoid adding any padding between the end of the array and the +// symbol delimiting its end. +#define BYTE_ALIGNMENT __declspec(align(1)) #pragma section(".SCOV$CA", read, write) // NOLINT -__declspec(allocate(".SCOV$CA")) __declspec(align(1)) uint64_t - __start___sancov_cntrs = 0; +__declspec(allocate(".SCOV$CA")) uint64_t __start___sancov_cntrs = 0; + +// Even though we tell the compiler not to align __stop__sancov_cntrs, the +// linker may try to align the section it is in (".SCOV$CZ"). Use a uint8_t so +// that it doesn't matter if the linker tries to align the section on a boundary +// of its size (no padding bytes are needed to pad to 1 byte boundaries). #pragma section(".SCOV$CZ", read, write) // NOLINT -__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint64_t - __stop___sancov_cntrs = 0; +__declspec(allocate(".SCOV$CZ")) + BYTE_ALIGNMENT uint8_t __stop___sancov_cntrs = 0; +#pragma section(".SCOV$GA", read, write) // NOLINT +__declspec(allocate(".SCOV$GA")) uint64_t __start___sancov_guards = 0; +#pragma section(".SCOV$GZ", read, write) // NOLINT +__declspec(allocate(".SCOV$GZ")) + BYTE_ALIGNMENT uint8_t __stop___sancov_guards = 0; + +// The Guard array and counter array should both be merged into the .data +// section to reduce the number of PE sections. However, because PCTable is +// constant it should be merged with the .rdata section. #pragma comment(linker, "/MERGE:.SCOV=.data") // Use uint64_t so there won't be any issues if the linker tries to word align -// the pc array. +// the PCTable. On x64 each element in the PCTable is 8 bytes so if the linker +// tries to word align the array, it will always start at the first byte after +// the end of this symbol. We make __start__sancov_cntrs and +// __start__sancov_guards 64 bit numbers so that the start of any of these +// arrays is always 8 bytes from the address of the "__start" symbol. #pragma section(".SCOVP$A", read) // NOLINT -__declspec(allocate(".SCOVP$A")) __declspec(align(1)) uint64_t - __start___sancov_pcs = 0; +__declspec(allocate(".SCOVP$A")) uint64_t __start___sancov_pcs = 0; #pragma section(".SCOVP$Z", read) // NOLINT -__declspec(allocate(".SCOVP$Z")) __declspec(align(1)) uint64_t - __stop___sancov_pcs = 0; +__declspec(allocate(".SCOVP$Z")) BYTE_ALIGNMENT uint8_t __stop___sancov_pcs = 0; #pragma comment(linker, "/MERGE:.SCOVP=.rdata") }