diff options
-rw-r--r-- | cmake/config-ix.cmake | 5 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerDefs.h | 7 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerIO.cpp | 8 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerIO.h | 2 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerIOPosix.cpp | 7 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerIOWindows.cpp | 20 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerTracePC.cpp | 3 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerUtilWindows.cpp | 4 | ||||
-rw-r--r-- | lib/fuzzer/tests/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/fuzzer/tests/FuzzerUnittest.cpp | 7 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_coverage_win_sections.cc | 53 | ||||
-rw-r--r-- | test/CMakeLists.txt | 5 |
12 files changed, 103 insertions, 20 deletions
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index f3935ffd6..1c60c3d03 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -619,7 +619,10 @@ else() 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" AND + # TODO: Support builds with MSVC. + NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" AND + NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") set(COMPILER_RT_HAS_FUZZER TRUE) else() set(COMPILER_RT_HAS_FUZZER FALSE) diff --git a/lib/fuzzer/FuzzerDefs.h b/lib/fuzzer/FuzzerDefs.h index a35c7a181..31655d562 100644 --- a/lib/fuzzer/FuzzerDefs.h +++ b/lib/fuzzer/FuzzerDefs.h @@ -129,8 +129,15 @@ #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 { diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index f3ead0ec5..dac5ec658 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -100,14 +100,6 @@ std::string DirPlusFile(const std::string &DirPath, return DirPath + GetSeparator() + FileName; } -std::string Basename(const std::string &Path, char Separator) { - size_t Pos = Path.rfind(Separator); - if (Pos == std::string::npos) - return Path; - assert(Pos < Path.size()); - return Path.substr(Pos + 1); -} - void DupAndCloseStderr() { int OutputFd = DuplicateFile(2); if (OutputFd > 0) { diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index 6d7757435..b4a68190e 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -68,7 +68,7 @@ void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V); char GetSeparator(); // Similar to the basename utility: returns the file name w/o the dir prefix. -std::string Basename(const std::string &Path, char Separator = GetSeparator()); +std::string Basename(const std::string &Path); FILE* OpenFile(int Fd, const char *Mode); diff --git a/lib/fuzzer/FuzzerIOPosix.cpp b/lib/fuzzer/FuzzerIOPosix.cpp index 17e884d3c..401b4cbbf 100644 --- a/lib/fuzzer/FuzzerIOPosix.cpp +++ b/lib/fuzzer/FuzzerIOPosix.cpp @@ -46,6 +46,13 @@ size_t FileSize(const std::string &Path) { return St.st_size; } +std::string Basename(const std::string &Path) { + size_t Pos = Path.rfind(GetSeparator()); + if (Pos == std::string::npos) return Path; + assert(Pos < Path.size()); + return Path.substr(Pos + 1); +} + void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, Vector<std::string> *V, bool TopDir) { auto E = GetEpoch(Dir); diff --git a/lib/fuzzer/FuzzerIOWindows.cpp b/lib/fuzzer/FuzzerIOWindows.cpp index 74853646b..314b79d0f 100644 --- a/lib/fuzzer/FuzzerIOWindows.cpp +++ b/lib/fuzzer/FuzzerIOWindows.cpp @@ -72,6 +72,26 @@ bool IsFile(const std::string &Path) { return IsFile(Path, Att); } +std::string Basename(const std::string &Path) { + size_t Pos = Path.find_last_of("/\\"); + if (Pos == std::string::npos) return Path; + assert(Pos < Path.size()); + return Path.substr(Pos + 1); +} + +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<std::string> *V, bool TopDir) { auto E = GetEpoch(Dir); diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp index 1aba816e8..75130840c 100644 --- a/lib/fuzzer/FuzzerTracePC.cpp +++ b/lib/fuzzer/FuzzerTracePC.cpp @@ -32,8 +32,7 @@ ATTRIBUTE_INTERFACE uintptr_t __sancov_trace_pc_pcs[fuzzer::TracePC::kNumPCs]; // Used by -fsanitize-coverage=stack-depth to track stack depth -ATTRIBUTE_INTERFACE __attribute__((tls_model("initial-exec"))) -thread_local uintptr_t __sancov_lowest_stack; +ATTRIBUTES_INTERFACE_TLS_INITIAL_EXEC uintptr_t __sancov_lowest_stack; namespace fuzzer { diff --git a/lib/fuzzer/FuzzerUtilWindows.cpp b/lib/fuzzer/FuzzerUtilWindows.cpp index 8227e778e..257723b60 100644 --- a/lib/fuzzer/FuzzerUtilWindows.cpp +++ b/lib/fuzzer/FuzzerUtilWindows.cpp @@ -179,7 +179,9 @@ const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, } std::string DisassembleCmd(const std::string &FileName) { - if (ExecuteCommand("dumpbin /summary > nul") == 0) + Vector<std::string> 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); diff --git a/lib/fuzzer/tests/CMakeLists.txt b/lib/fuzzer/tests/CMakeLists.txt index ed5807168..0b561c170 100644 --- a/lib/fuzzer/tests/CMakeLists.txt +++ b/lib/fuzzer/tests/CMakeLists.txt @@ -17,6 +17,8 @@ list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++) 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() diff --git a/lib/fuzzer/tests/FuzzerUnittest.cpp b/lib/fuzzer/tests/FuzzerUnittest.cpp index e3b067026..7cdd44582 100644 --- a/lib/fuzzer/tests/FuzzerUnittest.cpp +++ b/lib/fuzzer/tests/FuzzerUnittest.cpp @@ -34,6 +34,13 @@ TEST(Fuzzer, Basename) { EXPECT_EQ(Basename("/bar"), "bar"); EXPECT_EQ(Basename("foo/x"), "x"); EXPECT_EQ(Basename("foo/"), ""); +#if LIBFUZZER_WINDOWS + EXPECT_EQ(Basename("foo\\bar"), "bar"); + EXPECT_EQ(Basename("foo\\bar/baz"), "baz"); + EXPECT_EQ(Basename("\\bar"), "bar"); + EXPECT_EQ(Basename("foo\\x"), "x"); + EXPECT_EQ(Basename("foo\\"), ""); +#endif } TEST(Fuzzer, CrossOver) { diff --git a/lib/sanitizer_common/sanitizer_coverage_win_sections.cc b/lib/sanitizer_common/sanitizer_coverage_win_sections.cc index 4b0bbf1ed..108f76eff 100644 --- a/lib/sanitizer_common/sanitizer_coverage_win_sections.cc +++ b/lib/sanitizer_common/sanitizer_coverage_win_sections.cc @@ -7,16 +7,57 @@ // //===----------------------------------------------------------------------===// // -// This file defines delimiters for Sanitizer Coverage's section. +// This file defines delimiters for Sanitizer Coverage's section. It contains +// Windows specific tricks to coax the linker into giving us the start and stop +// addresses of a section, as ELF linkers can do, to get the size of certain +// arrays. According to https://msdn.microsoft.com/en-us/library/7977wcck.aspx +// sections with the same name before "$" are sorted alphabetically by the +// string that comes after "$" and merged into one section. We take advantage +// of this by putting data we want the size of into the middle (M) of a section, +// by using the letter "M" after "$". We get the start of this data (ie: +// __start_section_name) by making the start variable come at the start of the +// section (using the letter A after "$"). We do the same to get the end of the +// data by using the letter "Z" after "$" to make the end variable come after +// the data. Note that because of our technique the address of the start +// variable is actually the address of data that comes before our middle +// section. We also need to prevent the linker from adding any padding. Each +// technique we use for this is explained in the comments below. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_WINDOWS #include <stdint.h> -#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; +// 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; + +#pragma section(".SCOV$CA", read, write) // NOLINT +__declspec(allocate(".SCOV$CA")) __declspec(align(1)) uint64_t + __start___sancov_cntrs = 0; +#pragma section(".SCOV$CZ", read, write) // NOLINT +__declspec(allocate(".SCOV$CZ")) __declspec(align(1)) uint64_t + __stop___sancov_cntrs = 0; + +#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. +#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; + +#pragma comment(linker, "/MERGE:.SCOVP=.rdata") } -#endif // SANITIZER_WINDOWS +#endif // SANITIZER_WINDOWS diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 554ba5fa0..0a3fc0254 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -62,7 +62,10 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) compiler_rt_test_runtime(sanitizer_common) # OpenBSD not supporting asan, cannot run the tests - if(COMPILER_RT_BUILD_LIBFUZZER AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD" AND NOT ANDROID) + # Tests are broken for now on Windows + if(COMPILER_RT_BUILD_LIBFUZZER + AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD" + AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" AND NOT ANDROID) compiler_rt_test_runtime(fuzzer) endif() |