diff --git a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp --- a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp @@ -71,6 +71,35 @@ return IsFile(Path, Att); } +static bool IsFile(DWORD FileAttributes) { + if (FileAttributes == INVALID_FILE_ATTRIBUTES) + return false; + + // It isn't possible to tell if something is a file directly (Checking for + // FILE_ATTRIBUTE_NORMAL will break). Most implementations do this to decide + // if something is a "normal" file. Note we don't want to use _stat since it + // is very slow on Windows. + return (FileAttributes & + (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY)) == 0; +} + +static bool IsDir(DWORD FileAttrs) { + if (FileAttrs == INVALID_FILE_ATTRIBUTES) + return false; + + if (FileAttrs & FILE_ATTRIBUTE_DIRECTORY) + return true; + // FileAttrs describes a non-directory. + return false; +} + +static bool IsLink(DWORD FileAttributes) { + if (FileAttributes == INVALID_FILE_ATTRIBUTES) + return false; + + return FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT; +} + std::string Basename(const std::string &Path) { size_t Pos = Path.find_last_of("/\\"); if (Pos == std::string::npos) return Path; @@ -81,8 +110,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; @@ -140,13 +171,56 @@ *Epoch = E; } - 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) + return; // Directory is empty, nothing abnormal here. + // Something weird happened. + Printf("FindFirstFileA failed with error %d for directory: %s; exiting\n", + LastError, Dir.c_str()); + exit(1); + } + + 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 (IsFile(PathAttrs) || IsLink(PathAttrs)) { + FileCallback(Path); + } + } while (FindNextFileA(FindHandle, &FindInfo)); + + DWORD LastError = GetLastError(); + if (LastError != ERROR_NO_MORE_FILES) + Printf("FindNextFileA failed (Error code: %lu).\n", LastError); + + FindClose(FindHandle); + DirPostCallback(Dir); } char GetSeparator() { @@ -346,11 +420,11 @@ } void MkDir(const std::string &Path) { - Printf("MkDir: unimplemented\n"); + CreateDirectoryA(Path.c_str(), nullptr); } void RmDir(const std::string &Path) { - Printf("RmDir: unimplemented\n"); + RemoveDirectoryA(Path.c_str()); } } // namespace fuzzer diff --git a/compiler-rt/test/fuzzer/fork-sigusr.test b/compiler-rt/test/fuzzer/fork-sigusr.test --- 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 --- 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 @@ 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