diff options
| author | Jonathan Metzman <metzman@chromium.org> | 2019-02-27 19:27:16 +0000 |
|---|---|---|
| committer | Jonathan Metzman <metzman@chromium.org> | 2019-02-27 19:27:16 +0000 |
| commit | 518514e81d46d5ceb4f1d3cca3b6ce5f61ccb5d9 (patch) | |
| tree | 33c48f86bd4753d2f6c13f0c495eb03d62c922d0 | |
| parent | 6eef7d05249fb88bf5b31289f4c27d75f50c1ae4 (diff) | |
| download | bcm5719-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.cpp | 9 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerIO.h | 2 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp | 5 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp | 71 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerMerge.cpp | 2 | ||||
| -rw-r--r-- | compiler-rt/test/fuzzer/fork-sigusr.test | 3 | ||||
| -rw-r--r-- | compiler-rt/test/fuzzer/fork.test | 5 |
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 |

