Index: clang/lib/Driver/ToolChains/MSVC.cpp =================================================================== --- clang/lib/Driver/ToolChains/MSVC.cpp +++ clang/lib/Driver/ToolChains/MSVC.cpp @@ -365,6 +365,17 @@ CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); } + if (TC.getSanitizerArgs().needsFuzzer()) { + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back( + Args.MakeArgString(std::string("-wholearchive:") + + TC.getCompilerRTArgString(Args, "fuzzer", false))); + CmdArgs.push_back(Args.MakeArgString("-debug")); + // Prevent the linker from padding sections we use for instrumentation + // arrays. + CmdArgs.push_back(Args.MakeArgString("-incremental:no")); + } + if (TC.getSanitizerArgs().needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); @@ -1298,6 +1309,8 @@ SanitizerMask MSVCToolChain::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; Res &= ~SanitizerKind::CFIMFCall; return Res; } Index: compiler-rt/cmake/config-ix.cmake =================================================================== --- compiler-rt/cmake/config-ix.cmake +++ compiler-rt/cmake/config-ix.cmake @@ -619,7 +619,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND FUZZER_SUPPORTED_ARCH AND - OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|FreeBSD|OpenBSD|Fuchsia") + 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/FuzzerIOWindows.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp +++ compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp @@ -72,6 +72,19 @@ return IsFile(Path, Att); } +size_t FileSize(const std::string& Path) { + WIN32_FILE_ATTRIBUTE_DATA attr; + if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) { + Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n", + Path.c_str(), GetLastError()); + return 0; + } + ULARGE_INTEGER size; + size.HighPart = attr.nFileSizeHigh; + size.LowPart = attr.nFileSizeLow; + return size.QuadPart; +} + void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, Vector *V, bool TopDir) { auto E = GetEpoch(Dir); Index: compiler-rt/lib/fuzzer/FuzzerTracePC.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerTracePC.cpp +++ compiler-rt/lib/fuzzer/FuzzerTracePC.cpp @@ -31,9 +31,12 @@ ATTRIBUTE_INTERFACE uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; +// Disable on Windows since it is not a main feature and causes a compilation error. +#if !LIBFUZZER_WINDOWS // Used by -fsanitize-coverage=stack-depth to track stack depth ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) thread_local uintptr_t __sancov_lowest_stack; +#endif namespace fuzzer { @@ -458,12 +461,18 @@ ATTRIBUTE_NO_SANITIZE_ALL void TracePC::RecordInitialStack() { +#if !LIBFUZZER_WINDOWS int stack; __sancov_lowest_stack = InitialStack = reinterpret_cast(&stack); +#endif } uintptr_t TracePC::GetMaxStackOffset() const { +#if !LIBFUZZER_WINDOWS return InitialStack - __sancov_lowest_stack; // Stack grows down +#else + return 0; +#endif } } // namespace fuzzer @@ -496,12 +505,26 @@ ATTRIBUTE_INTERFACE void __sanitizer_cov_8bit_counters_init(uint8_t *Start, uint8_t *Stop) { + // On Windows, Start actually points to a uint64_t located before the counter + // array (see sanitizer_coverage_win_sections.cc for why). So we need to + // to update Start to point to the counter array. +#if LIBFUZZER_WINDOWS + Start += sizeof(uint64_t); +#endif fuzzer::TPC.HandleInline8bitCountersInit(Start, Stop); } ATTRIBUTE_INTERFACE void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, const uintptr_t *pcs_end) { + // On Windows, pcs_beg actually points to a uint64_t located before the pc + // array (see sanitizer_coverage_win_sections.cc for why). So we need to + // to update pcs_beg to point to the pc array. +#if LIBFUZZER_WINDOWS + const uint8_t *pcs_beg_8bit = (const uint8_t *)pcs_beg; + pcs_beg_8bit += sizeof(uint64_t); + pcs_beg = (const uintptr_t *)pcs_beg_8bit; +#endif fuzzer::TPC.HandlePCsInit(pcs_beg, pcs_end); } Index: compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp =================================================================== --- compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp +++ compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp @@ -179,7 +179,9 @@ } std::string DisassembleCmd(const std::string &FileName) { - if (ExecuteCommand("dumpbin /summary > nul") == 0) + Vector command_vector; + command_vector.push_back("dumpbin /summary > nul"); + if (ExecuteCommand(Command(command_vector)) == 0) return "dumpbin /disasm " + FileName; Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); exit(1); Index: compiler-rt/lib/fuzzer/tests/CMakeLists.txt =================================================================== --- compiler-rt/lib/fuzzer/tests/CMakeLists.txt +++ compiler-rt/lib/fuzzer/tests/CMakeLists.txt @@ -17,6 +17,8 @@ if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lc++ -lpthread) +elseif(WIN32) + list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++) else() list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS -lstdc++ -lpthread) endif() Index: compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp =================================================================== --- compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp +++ compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -29,11 +29,18 @@ } TEST(Fuzzer, Basename) { - EXPECT_EQ(Basename("foo/bar"), "bar"); EXPECT_EQ(Basename("bar"), "bar"); +#if !LIBFUZZER_WINDOWS + EXPECT_EQ(Basename("foo/bar"), "bar"); EXPECT_EQ(Basename("/bar"), "bar"); EXPECT_EQ(Basename("foo/x"), "x"); EXPECT_EQ(Basename("foo/"), ""); +#else + EXPECT_EQ(Basename("foo\\bar"), "bar"); + EXPECT_EQ(Basename("\\bar"), "bar"); + EXPECT_EQ(Basename("foo\\x"), "x"); + EXPECT_EQ(Basename("foo\\"), ""); +#endif } TEST(Fuzzer, CrossOver) { 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 @@ -13,10 +13,24 @@ #include "sanitizer_platform.h" #if SANITIZER_WINDOWS #include -#pragma section(".SCOV$A", read, write) // NOLINT -#pragma section(".SCOV$Z", read, write) // NOLINT extern "C" { -__declspec(allocate(".SCOV$A")) uint32_t __start___sancov_guards = 0; -__declspec(allocate(".SCOV$Z")) uint32_t __stop___sancov_guards = 0; +#pragma section(".SCOVG$A", read, write) // NOLINT +__declspec(allocate(".SCOVG$A")) uint32_t __start___sancov_guards = 0; +#pragma section(".SCOVG$Z", read, write) // NOLINT +__declspec(allocate(".SCOVG$Z")) uint32_t __stop___sancov_guards = 0; + +// Use align(1) to avoid adding any padding that will mess up clients trying to +// determine the start and end of the array. +#pragma section(".SCOVC$A", read, write) // NOLINT +__declspec(allocate(".SCOVC$A")) __declspec(align(1)) uint64_t __start___sancov_cntrs = 0; +#pragma section(".SCOVC$Z", read, write) // NOLINT +__declspec(allocate(".SCOVC$Z")) __declspec(align(1)) uint64_t __stop___sancov_cntrs = 0; + +// Use uint64_t so there won't be any issues if the linker tries to word align +// the pc array. +#pragma section(".SCOVP$A", read) // NOLINT +__declspec(allocate(".SCOVP$A")) __declspec(align(1)) 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; } #endif // SANITIZER_WINDOWS Index: compiler-rt/test/fuzzer/afl-driver-extra-stats.test =================================================================== --- compiler-rt/test/fuzzer/afl-driver-extra-stats.test +++ compiler-rt/test/fuzzer/afl-driver-extra-stats.test @@ -1,4 +1,6 @@ XFAIL: ios +# AFL doesn't work on windows. +UNSUPPORTED: windows RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest ; Test that not specifying an extra stats file isn't broken. Index: compiler-rt/test/fuzzer/afl-driver-stderr.test =================================================================== --- compiler-rt/test/fuzzer/afl-driver-stderr.test +++ compiler-rt/test/fuzzer/afl-driver-stderr.test @@ -1,5 +1,6 @@ XFAIL: ios -UNSUPPORTED: freebsd +# AFL doesn't work on windows. +UNSUPPORTED: freebsd, windows RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest ; Test that not specifying a stderr file isn't broken. Index: compiler-rt/test/fuzzer/cleanse.test =================================================================== --- compiler-rt/test/fuzzer/cleanse.test +++ compiler-rt/test/fuzzer/cleanse.test @@ -1,3 +1,5 @@ +# Piping is not available on windows. +UNSUPPORTED: windows RUN: %cpp_compiler %S/CleanseTest.cpp -o %t-CleanseTest RUN: echo -n 0123456789ABCDEFGHIZ > %t-in RUN: %run %t-CleanseTest -cleanse_crash=1 %t-in -exact_artifact_path=%t-out Index: compiler-rt/test/fuzzer/coverage.test =================================================================== --- compiler-rt/test/fuzzer/coverage.test +++ compiler-rt/test/fuzzer/coverage.test @@ -1,4 +1,5 @@ -UNSUPPORTED: aarch64 +# -fPIC doesn't work for .exes. +UNSUPPORTED: aarch64, windows RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/NullDerefTest.cpp -o %t-NullDerefTest RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO1.cpp -fPIC %ld_flags_rpath_so1 -shared -o %dynamiclib1 RUN: %cpp_compiler -mllvm -use-unknown-locations=Disable %S/DSO2.cpp -fPIC %ld_flags_rpath_so2 -shared -o %dynamiclib2 Index: compiler-rt/test/fuzzer/dso.test =================================================================== --- compiler-rt/test/fuzzer/dso.test +++ compiler-rt/test/fuzzer/dso.test @@ -1,3 +1,5 @@ +# -fPIC doesn't work for .exes. +UNSUPPORTED: windows RUN: %cpp_compiler %S/DSO1.cpp -fPIC %ld_flags_rpath_so1 -shared -o %dynamiclib1 RUN: %cpp_compiler %S/DSO2.cpp -fPIC %ld_flags_rpath_so2 -shared -o %dynamiclib2 RUN: %cpp_compiler %S/DSOTestMain.cpp %S/DSOTestExtra.cpp %ld_flags_rpath_exe1 %ld_flags_rpath_exe2 -o %t-DSOTest Index: compiler-rt/test/fuzzer/dump_coverage.test =================================================================== --- compiler-rt/test/fuzzer/dump_coverage.test +++ compiler-rt/test/fuzzer/dump_coverage.test @@ -1,4 +1,5 @@ -UNSUPPORTED: freebsd +# -fPIC doesn't work for .exes. +UNSUPPORTED: freebsd, windows RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO1.cpp -fPIC -shared -o %dynamiclib1 %ld_flags_rpath_so1 RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSO2.cpp -fPIC -shared -o %dynamiclib2 %ld_flags_rpath_so2 RUN: %cpp_compiler -fsanitize-coverage=0 -fsanitize-coverage=trace-pc-guard %S/DSOTestMain.cpp %S/DSOTestExtra.cpp %ld_flags_rpath_exe1 %ld_flags_rpath_exe2 -o %t-DSOTest Index: compiler-rt/test/fuzzer/initialize.test =================================================================== --- compiler-rt/test/fuzzer/initialize.test +++ compiler-rt/test/fuzzer/initialize.test @@ -1,3 +1,5 @@ +# memmove is a GNUism and is not available on Windows. +UNSUPPORTED: windows CHECK: BINGO RUN: %cpp_compiler %S/InitializeTest.cpp -o %t-InitializeTest RUN: not %run %t-InitializeTest -use_value_profile=1 2>&1 | FileCheck %s Index: compiler-rt/test/fuzzer/standalone.test =================================================================== --- compiler-rt/test/fuzzer/standalone.test +++ compiler-rt/test/fuzzer/standalone.test @@ -1,3 +1,5 @@ +# memmove is a GNUism and is not available on Windows. +UNSUPPORTED: windows RUN: %no_fuzzer_c_compiler %libfuzzer_src/standalone/StandaloneFuzzTargetMain.c -c -o %t_1.o RUN: %no_fuzzer_cpp_compiler %S/InitializeTest.cpp -c -o %t_2.o Index: llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -809,8 +809,13 @@ std::string SanitizerCoverageModule::getSectionName(const std::string &Section) const { - if (TargetTriple.getObjectFormat() == Triple::COFF) - return ".SCOV$M"; + if (TargetTriple.getObjectFormat() == Triple::COFF) { + if (Section == SanCovCountersSectionName) + return ".SCOVC$M"; + else if (Section == SanCovPCsSectionName) + return ".SCOVP$M"; + return ".SCOVG$M"; // For SanCovGuardsSectionName. + } if (TargetTriple.isOSBinFormatMachO()) return "__DATA,__" + Section; return "__" + Section;