[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.

Patch By: metzman

Reviewers: morehouse, rnk

Reviewed By: morehouse, rnk

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

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

llvm-svn: 341082
GitOrigin-RevId: 7e042bb1d18a06fc4b67143b5615acb15b4b8c57
diff --git a/FuzzerDefs.h b/FuzzerDefs.h
index a35c7a1..31655d5 100644
--- a/FuzzerDefs.h
+++ b/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/FuzzerIO.cpp b/FuzzerIO.cpp
index f3ead0e..dac5ec6 100644
--- a/FuzzerIO.cpp
+++ b/FuzzerIO.cpp
@@ -100,14 +100,6 @@
   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/FuzzerIO.h b/FuzzerIO.h
index 6d77574..b4a6819 100644
--- a/FuzzerIO.h
+++ b/FuzzerIO.h
@@ -68,7 +68,7 @@
 
 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/FuzzerIOPosix.cpp b/FuzzerIOPosix.cpp
index 17e884d..401b4cb 100644
--- a/FuzzerIOPosix.cpp
+++ b/FuzzerIOPosix.cpp
@@ -46,6 +46,13 @@
   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/FuzzerIOWindows.cpp b/FuzzerIOWindows.cpp
index 7485364..314b79d 100644
--- a/FuzzerIOWindows.cpp
+++ b/FuzzerIOWindows.cpp
@@ -72,6 +72,26 @@
   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/FuzzerTracePC.cpp b/FuzzerTracePC.cpp
index 1aba816..7513084 100644
--- a/FuzzerTracePC.cpp
+++ b/FuzzerTracePC.cpp
@@ -32,8 +32,7 @@
 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/FuzzerUtilWindows.cpp b/FuzzerUtilWindows.cpp
index 8227e77..257723b 100644
--- a/FuzzerUtilWindows.cpp
+++ b/FuzzerUtilWindows.cpp
@@ -179,7 +179,9 @@
 }
 
 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/tests/FuzzerUnittest.cpp b/tests/FuzzerUnittest.cpp
index e3b0670..7cdd445 100644
--- a/tests/FuzzerUnittest.cpp
+++ b/tests/FuzzerUnittest.cpp
@@ -34,6 +34,13 @@
   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) {