[compiler-rt] r340949 - [libFuzzer] Port to Windows

Matt Morehouse via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 29 11:08:34 PDT 2018


Author: morehouse
Date: Wed Aug 29 11:08:34 2018
New Revision: 340949

URL: http://llvm.org/viewvc/llvm-project?rev=340949&view=rev
Log:
[libFuzzer] Port to Windows

Summary:
Port libFuzzer to windows-msvc.
This patch allows libFuzzer targets to be built and run on Windows, using -fsanitize=fuzzer and/or fsanitize=fuzzer-no-link. It allows these forms of coverage instrumentation to work on Windows as well.
It does not fix all issues, such as those with -fsanitize-coverage=stack-depth, which is not usable on Windows as of this patch.
It also does not fix any libFuzzer integration tests. Nearly all of them fail to compile, fixing them will come in a later patch, so libFuzzer tests are disabled on Windows until them.

Reviewers: morehouse, rnk

Reviewed By: morehouse, rnk

Subscribers: #sanitizers, delcypher, morehouse, kcc, eraman

Differential Revision: https://reviews.llvm.org/D51022

Modified:
    compiler-rt/trunk/cmake/config-ix.cmake
    compiler-rt/trunk/lib/fuzzer/FuzzerDefs.h
    compiler-rt/trunk/lib/fuzzer/FuzzerIO.cpp
    compiler-rt/trunk/lib/fuzzer/FuzzerIO.h
    compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp
    compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp
    compiler-rt/trunk/lib/fuzzer/FuzzerTracePC.cpp
    compiler-rt/trunk/lib/fuzzer/FuzzerUtilWindows.cpp
    compiler-rt/trunk/lib/fuzzer/tests/CMakeLists.txt
    compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_win_sections.cc
    compiler-rt/trunk/test/CMakeLists.txt

Modified: compiler-rt/trunk/cmake/config-ix.cmake
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/cmake/config-ix.cmake?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/cmake/config-ix.cmake (original)
+++ compiler-rt/trunk/cmake/config-ix.cmake Wed Aug 29 11:08:34 2018
@@ -619,7 +619,7 @@ 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")
   set(COMPILER_RT_HAS_FUZZER TRUE)
 else()
   set(COMPILER_RT_HAS_FUZZER FALSE)

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerDefs.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerDefs.h?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerDefs.h (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerDefs.h Wed Aug 29 11:08:34 2018
@@ -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 {

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerIO.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerIO.cpp?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerIO.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerIO.cpp Wed Aug 29 11:08:34 2018
@@ -100,14 +100,6 @@ std::string DirPlusFile(const std::strin
   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) {

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerIO.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerIO.h?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerIO.h (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerIO.h Wed Aug 29 11:08:34 2018
@@ -68,7 +68,7 @@ void GetSizedFilesFromDir(const std::str
 
 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);
 

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp Wed Aug 29 11:08:34 2018
@@ -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);

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp Wed Aug 29 11:08:34 2018
@@ -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);

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerTracePC.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerTracePC.cpp?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerTracePC.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerTracePC.cpp Wed Aug 29 11:08:34 2018
@@ -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 {
 

Modified: compiler-rt/trunk/lib/fuzzer/FuzzerUtilWindows.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/FuzzerUtilWindows.cpp?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/FuzzerUtilWindows.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/FuzzerUtilWindows.cpp Wed Aug 29 11:08:34 2018
@@ -179,7 +179,9 @@ const void *SearchMemory(const void *Dat
 }
 
 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);

Modified: compiler-rt/trunk/lib/fuzzer/tests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/tests/CMakeLists.txt?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/tests/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/fuzzer/tests/CMakeLists.txt Wed Aug 29 11:08:34 2018
@@ -17,6 +17,8 @@ list(APPEND LIBFUZZER_UNITTEST_LINK_FLAG
 
 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()

Modified: compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp (original)
+++ compiler-rt/trunk/lib/fuzzer/tests/FuzzerUnittest.cpp Wed Aug 29 11:08:34 2018
@@ -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) {

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_win_sections.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_win_sections.cc?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_win_sections.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_coverage_win_sections.cc Wed Aug 29 11:08:34 2018
@@ -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

Modified: compiler-rt/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/CMakeLists.txt?rev=340949&r1=340948&r2=340949&view=diff
==============================================================================
--- compiler-rt/trunk/test/CMakeLists.txt (original)
+++ compiler-rt/trunk/test/CMakeLists.txt Wed Aug 29 11:08:34 2018
@@ -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()
 




More information about the llvm-commits mailing list