summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Metzman <metzman@chromium.org>2019-02-27 19:27:16 +0000
committerJonathan Metzman <metzman@chromium.org>2019-02-27 19:27:16 +0000
commit518514e81d46d5ceb4f1d3cca3b6ce5f61ccb5d9 (patch)
tree33c48f86bd4753d2f6c13f0c495eb03d62c922d0
parent6eef7d05249fb88bf5b31289f4c27d75f50c1ae4 (diff)
downloadbcm5719-llvm-518514e81d46d5ceb4f1d3cca3b6ce5f61ccb5d9.tar.gz
bcm5719-llvm-518514e81d46d5ceb4f1d3cca3b6ce5f61ccb5d9.zip
[libFuzzer][Windows] Port fork mode to Windows
Summary: Port libFuzzer's fork mode to Windows. Implement Windows versions of MkDir, RmDir, and IterateDirRecursive to do this. Don't print error messages under new normal uses of FileSize (on a non-existent file). Implement portable way of piping output to /dev/null. Fix test for Windows and comment fork-sigusr.test on why it won't be ported to Win. Reviewers: zturner Reviewed By: zturner Subscribers: kcc, zturner, jdoerfert, #sanitizers, llvm-commits Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D58513 llvm-svn: 355019
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerFork.cpp9
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerIO.h2
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp5
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp71
-rw-r--r--compiler-rt/lib/fuzzer/FuzzerMerge.cpp2
-rw-r--r--compiler-rt/test/fuzzer/fork-sigusr.test3
-rw-r--r--compiler-rt/test/fuzzer/fork.test5
7 files changed, 81 insertions, 16 deletions
diff --git a/compiler-rt/lib/fuzzer/FuzzerFork.cpp b/compiler-rt/lib/fuzzer/FuzzerFork.cpp
index 1f7fe9b3372..52a233f05ed 100644
--- a/compiler-rt/lib/fuzzer/FuzzerFork.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerFork.cpp
@@ -304,13 +304,13 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
}
Stop = true;
- // The workers have already finished doing useful work, or
- // we were interrupted. Either way, cleanup up now.
- RmDirRecursive(Env.TempDir);
-
for (auto &T : Threads)
T.join();
+ // The workers have terminated. Don't try to remove the directory before they
+ // terminate to avoid a race condition preventing cleanup on Windows.
+ RmDirRecursive(Env.TempDir);
+
// Use the exit code from the last child process.
Printf("INFO: exiting: %d time: %zds\n", ExitCode,
Env.secondsSinceProcessStartUp());
@@ -318,4 +318,3 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options,
}
} // namespace fuzzer
-
diff --git a/compiler-rt/lib/fuzzer/FuzzerIO.h b/compiler-rt/lib/fuzzer/FuzzerIO.h
index e51b8d1b082..9d4e7650a29 100644
--- a/compiler-rt/lib/fuzzer/FuzzerIO.h
+++ b/compiler-rt/lib/fuzzer/FuzzerIO.h
@@ -97,6 +97,8 @@ intptr_t GetHandleFromFd(int fd);
void MkDir(const std::string &Path);
void RmDir(const std::string &Path);
+const std::string &getDevNull();
+
} // namespace fuzzer
#endif // LLVM_FUZZER_IO_H
diff --git a/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp b/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp
index 92d19d3b69f..953848a8970 100644
--- a/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp
@@ -170,6 +170,11 @@ void RmDir(const std::string &Path) {
rmdir(Path.c_str());
}
+const std::string &getDevNull() {
+ static const std::string devNull = "/dev/null";
+ return devNull;
+}
+
} // namespace fuzzer
#endif // LIBFUZZER_POSIX
diff --git a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp
index e49e8a4c5f7..b8c200b810a 100644
--- a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp
@@ -71,6 +71,11 @@ bool IsFile(const std::string &Path) {
return IsFile(Path, Att);
}
+static bool IsDir(DWORD FileAttrs) {
+ if (FileAttrs == INVALID_FILE_ATTRIBUTES) return false;
+ return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
+}
+
std::string Basename(const std::string &Path) {
size_t Pos = Path.find_last_of("/\\");
if (Pos == std::string::npos) return Path;
@@ -81,8 +86,10 @@ std::string Basename(const std::string &Path) {
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());
+ DWORD LastError = GetLastError();
+ if (LastError != ERROR_FILE_NOT_FOUND)
+ Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
+ Path.c_str(), LastError);
return 0;
}
ULARGE_INTEGER size;
@@ -145,8 +152,51 @@ void IterateDirRecursive(const std::string &Dir,
void (*DirPreCallback)(const std::string &Dir),
void (*DirPostCallback)(const std::string &Dir),
void (*FileCallback)(const std::string &Dir)) {
- // Unimplemented.
- // TODO: implement, and then implement ListFilesInDirRecursive via this one.
+ // TODO(metzman): Implement ListFilesInDirRecursive via this function.
+ DirPreCallback(Dir);
+
+ DWORD DirAttrs = GetFileAttributesA(Dir.c_str());
+ if (!IsDir(DirAttrs)) return;
+
+ std::string TargetDir(Dir);
+ assert(!TargetDir.empty());
+ if (TargetDir.back() != '\\') TargetDir.push_back('\\');
+ TargetDir.push_back('*');
+
+ WIN32_FIND_DATAA FindInfo;
+ // Find the directory's first file.
+ HANDLE FindHandle = FindFirstFileA(TargetDir.c_str(), &FindInfo);
+ if (FindHandle == INVALID_HANDLE_VALUE) {
+ DWORD LastError = GetLastError();
+ if (LastError != ERROR_FILE_NOT_FOUND) {
+ // If the directory isn't empty, then something abnormal is going on.
+ Printf("FindFirstFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
+ LastError);
+ }
+ return;
+ }
+
+ do {
+ std::string Path = DirPlusFile(Dir, FindInfo.cFileName);
+ DWORD PathAttrs = FindInfo.dwFileAttributes;
+ if (IsDir(PathAttrs)) {
+ // Is Path the current directory (".") or the parent ("..")?
+ if (strcmp(FindInfo.cFileName, ".") == 0 ||
+ strcmp(FindInfo.cFileName, "..") == 0)
+ continue;
+ IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
+ } else if (PathAttrs != INVALID_FILE_ATTRIBUTES) {
+ FileCallback(Path);
+ }
+ } while (FindNextFileA(FindHandle, &FindInfo));
+
+ DWORD LastError = GetLastError();
+ if (LastError != ERROR_NO_MORE_FILES)
+ Printf("FindNextFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
+ LastError);
+
+ FindClose(FindHandle);
+ DirPostCallback(Dir);
}
char GetSeparator() {
@@ -346,11 +396,20 @@ void RawPrint(const char *Str) {
}
void MkDir(const std::string &Path) {
- Printf("MkDir: unimplemented\n");
+ if (CreateDirectoryA(Path.c_str(), nullptr)) return;
+ Printf("CreateDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
+ GetLastError());
}
void RmDir(const std::string &Path) {
- Printf("RmDir: unimplemented\n");
+ if (RemoveDirectoryA(Path.c_str())) return;
+ Printf("RemoveDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
+ GetLastError());
+}
+
+const std::string &getDevNull() {
+ static const std::string devNull = "NUL";
+ return devNull;
}
} // namespace fuzzer
diff --git a/compiler-rt/lib/fuzzer/FuzzerMerge.cpp b/compiler-rt/lib/fuzzer/FuzzerMerge.cpp
index d70aa3e901a..dace45ece1d 100644
--- a/compiler-rt/lib/fuzzer/FuzzerMerge.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerMerge.cpp
@@ -331,7 +331,7 @@ void CrashResistantMerge(const Vector<std::string> &Args,
Cmd.addFlag("merge_control_file", CFPath);
Cmd.addFlag("merge_inner", "1");
if (!V) {
- Cmd.setOutputFile("/dev/null"); // TODO: need to handle this on Windows?
+ Cmd.setOutputFile(getDevNull());
Cmd.combineOutAndErr();
}
auto ExitCode = ExecuteCommand(Cmd);
diff --git a/compiler-rt/test/fuzzer/fork-sigusr.test b/compiler-rt/test/fuzzer/fork-sigusr.test
index f00a8b387b8..ea2e56ca9c2 100644
--- a/compiler-rt/test/fuzzer/fork-sigusr.test
+++ b/compiler-rt/test/fuzzer/fork-sigusr.test
@@ -1,6 +1,5 @@
# Check that libFuzzer honors SIGUSR1/SIGUSR2
-# FIXME: Disabled on Windows for now because of reliance on posix only features
-# (eg: export, "&", pkill).
+# Disabled on Windows which does not have SIGUSR1/SIGUSR2.
UNSUPPORTED: darwin, windows
RUN: rm -rf %t
RUN: mkdir -p %t
diff --git a/compiler-rt/test/fuzzer/fork.test b/compiler-rt/test/fuzzer/fork.test
index 881880e5e13..393a9f66b4f 100644
--- a/compiler-rt/test/fuzzer/fork.test
+++ b/compiler-rt/test/fuzzer/fork.test
@@ -1,4 +1,4 @@
-# REQUIRES: linux
+# UNSUPPORTED: darwin, freebsd
BINGO: BINGO
RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest
RUN: not %run %t-SimpleTest -fork=1 2>&1 | FileCheck %s --check-prefix=BINGO
@@ -11,7 +11,8 @@ OOM: ERROR: libFuzzer: out-of-memory
RUN: %cpp_compiler %S/OutOfMemoryTest.cpp -o %t-OutOfMemoryTest
RUN: not %run %t-OutOfMemoryTest -fork=1 -ignore_ooms=0 -rss_limit_mb=128 2>&1 | FileCheck %s --check-prefix=OOM
-CRASH: SEGV on unknown address 0x000000000000
+# access-violation is the error thrown on Windows.
+CRASH: {{SEGV|access-violation}} on unknown address 0x000000000000
RUN: %cpp_compiler %S/ShallowOOMDeepCrash.cpp -o %t-ShallowOOMDeepCrash
RUN: not %run %t-ShallowOOMDeepCrash -fork=1 -rss_limit_mb=128 2>&1 | FileCheck %s --check-prefix=CRASH
OpenPOWER on IntegriCloud