Index: compiler-rt/trunk/lib/fuzzer/FuzzerFork.cpp =================================================================== --- compiler-rt/trunk/lib/fuzzer/FuzzerFork.cpp +++ compiler-rt/trunk/lib/fuzzer/FuzzerFork.cpp @@ -304,13 +304,13 @@ } 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 @@ } } // namespace fuzzer - Index: compiler-rt/trunk/lib/fuzzer/FuzzerIO.h =================================================================== --- compiler-rt/trunk/lib/fuzzer/FuzzerIO.h +++ compiler-rt/trunk/lib/fuzzer/FuzzerIO.h @@ -97,6 +97,8 @@ void MkDir(const std::string &Path); void RmDir(const std::string &Path); +const std::string &getDevNull(); + } // namespace fuzzer #endif // LLVM_FUZZER_IO_H Index: compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp =================================================================== --- compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp +++ compiler-rt/trunk/lib/fuzzer/FuzzerIOPosix.cpp @@ -170,6 +170,11 @@ rmdir(Path.c_str()); } +const std::string &getDevNull() { + static const std::string devNull = "/dev/null"; + return devNull; +} + } // namespace fuzzer #endif // LIBFUZZER_POSIX Index: compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp =================================================================== --- compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp +++ compiler-rt/trunk/lib/fuzzer/FuzzerIOWindows.cpp @@ -71,6 +71,11 @@ 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 @@ 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 (*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 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 Index: compiler-rt/trunk/lib/fuzzer/FuzzerMerge.cpp =================================================================== --- compiler-rt/trunk/lib/fuzzer/FuzzerMerge.cpp +++ compiler-rt/trunk/lib/fuzzer/FuzzerMerge.cpp @@ -331,7 +331,7 @@ 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); Index: compiler-rt/trunk/test/fuzzer/fork-sigusr.test =================================================================== --- compiler-rt/trunk/test/fuzzer/fork-sigusr.test +++ compiler-rt/trunk/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 Index: compiler-rt/trunk/test/fuzzer/fork.test =================================================================== --- compiler-rt/trunk/test/fuzzer/fork.test +++ compiler-rt/trunk/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 @@ 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