FuzzerIOWindows.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. //===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. // IO functions implementation for Windows.
  9. //===----------------------------------------------------------------------===//
  10. #include "FuzzerPlatform.h"
  11. #if LIBFUZZER_WINDOWS
  12. #include "FuzzerExtFunctions.h"
  13. #include "FuzzerIO.h"
  14. #include <cstdarg>
  15. #include <cstdio>
  16. #include <fstream>
  17. #include <io.h>
  18. #include <iterator>
  19. #include <sys/stat.h>
  20. #include <sys/types.h>
  21. #include <windows.h>
  22. namespace fuzzer {
  23. static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {
  24. if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
  25. return true;
  26. if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  27. return false;
  28. HANDLE FileHandle(
  29. CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  30. FILE_FLAG_BACKUP_SEMANTICS, 0));
  31. if (FileHandle == INVALID_HANDLE_VALUE) {
  32. Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
  33. GetLastError());
  34. return false;
  35. }
  36. DWORD FileType = GetFileType(FileHandle);
  37. if (FileType == FILE_TYPE_UNKNOWN) {
  38. Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
  39. GetLastError());
  40. CloseHandle(FileHandle);
  41. return false;
  42. }
  43. if (FileType != FILE_TYPE_DISK) {
  44. CloseHandle(FileHandle);
  45. return false;
  46. }
  47. CloseHandle(FileHandle);
  48. return true;
  49. }
  50. bool IsFile(const std::string &Path) {
  51. DWORD Att = GetFileAttributesA(Path.c_str());
  52. if (Att == INVALID_FILE_ATTRIBUTES) {
  53. Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
  54. Path.c_str(), GetLastError());
  55. return false;
  56. }
  57. return IsFile(Path, Att);
  58. }
  59. static bool IsDir(DWORD FileAttrs) {
  60. if (FileAttrs == INVALID_FILE_ATTRIBUTES) return false;
  61. return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
  62. }
  63. bool IsDirectory(const std::string &Path) {
  64. DWORD Att = GetFileAttributesA(Path.c_str());
  65. if (Att == INVALID_FILE_ATTRIBUTES) {
  66. Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
  67. Path.c_str(), GetLastError());
  68. return false;
  69. }
  70. return IsDir(Att);
  71. }
  72. std::string Basename(const std::string &Path) {
  73. size_t Pos = Path.find_last_of("/\\");
  74. if (Pos == std::string::npos) return Path;
  75. assert(Pos < Path.size());
  76. return Path.substr(Pos + 1);
  77. }
  78. size_t FileSize(const std::string &Path) {
  79. WIN32_FILE_ATTRIBUTE_DATA attr;
  80. if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
  81. DWORD LastError = GetLastError();
  82. if (LastError != ERROR_FILE_NOT_FOUND)
  83. Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
  84. Path.c_str(), LastError);
  85. return 0;
  86. }
  87. ULARGE_INTEGER size;
  88. size.HighPart = attr.nFileSizeHigh;
  89. size.LowPart = attr.nFileSizeLow;
  90. return size.QuadPart;
  91. }
  92. void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
  93. std::vector<std::string> *V, bool TopDir) {
  94. auto E = GetEpoch(Dir);
  95. if (Epoch)
  96. if (E && *Epoch >= E) return;
  97. std::string Path(Dir);
  98. assert(!Path.empty());
  99. if (Path.back() != '\\')
  100. Path.push_back('\\');
  101. Path.push_back('*');
  102. // Get the first directory entry.
  103. WIN32_FIND_DATAA FindInfo;
  104. HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
  105. if (FindHandle == INVALID_HANDLE_VALUE)
  106. {
  107. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  108. return;
  109. Printf("No such file or directory: %s; exiting\n", Dir.c_str());
  110. exit(1);
  111. }
  112. do {
  113. std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);
  114. if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  115. size_t FilenameLen = strlen(FindInfo.cFileName);
  116. if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
  117. (FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
  118. FindInfo.cFileName[1] == '.'))
  119. continue;
  120. ListFilesInDirRecursive(FileName, Epoch, V, false);
  121. }
  122. else if (IsFile(FileName, FindInfo.dwFileAttributes))
  123. V->push_back(FileName);
  124. } while (FindNextFileA(FindHandle, &FindInfo));
  125. DWORD LastError = GetLastError();
  126. if (LastError != ERROR_NO_MORE_FILES)
  127. Printf("FindNextFileA failed (Error code: %lu).\n", LastError);
  128. FindClose(FindHandle);
  129. if (Epoch && TopDir)
  130. *Epoch = E;
  131. }
  132. void IterateDirRecursive(const std::string &Dir,
  133. void (*DirPreCallback)(const std::string &Dir),
  134. void (*DirPostCallback)(const std::string &Dir),
  135. void (*FileCallback)(const std::string &Dir)) {
  136. // TODO(metzman): Implement ListFilesInDirRecursive via this function.
  137. DirPreCallback(Dir);
  138. DWORD DirAttrs = GetFileAttributesA(Dir.c_str());
  139. if (!IsDir(DirAttrs)) return;
  140. std::string TargetDir(Dir);
  141. assert(!TargetDir.empty());
  142. if (TargetDir.back() != '\\') TargetDir.push_back('\\');
  143. TargetDir.push_back('*');
  144. WIN32_FIND_DATAA FindInfo;
  145. // Find the directory's first file.
  146. HANDLE FindHandle = FindFirstFileA(TargetDir.c_str(), &FindInfo);
  147. if (FindHandle == INVALID_HANDLE_VALUE) {
  148. DWORD LastError = GetLastError();
  149. if (LastError != ERROR_FILE_NOT_FOUND) {
  150. // If the directory isn't empty, then something abnormal is going on.
  151. Printf("FindFirstFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
  152. LastError);
  153. }
  154. return;
  155. }
  156. do {
  157. std::string Path = DirPlusFile(Dir, FindInfo.cFileName);
  158. DWORD PathAttrs = FindInfo.dwFileAttributes;
  159. if (IsDir(PathAttrs)) {
  160. // Is Path the current directory (".") or the parent ("..")?
  161. if (strcmp(FindInfo.cFileName, ".") == 0 ||
  162. strcmp(FindInfo.cFileName, "..") == 0)
  163. continue;
  164. IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
  165. } else if (PathAttrs != INVALID_FILE_ATTRIBUTES) {
  166. FileCallback(Path);
  167. }
  168. } while (FindNextFileA(FindHandle, &FindInfo));
  169. DWORD LastError = GetLastError();
  170. if (LastError != ERROR_NO_MORE_FILES)
  171. Printf("FindNextFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
  172. LastError);
  173. FindClose(FindHandle);
  174. DirPostCallback(Dir);
  175. }
  176. char GetSeparator() {
  177. return '\\';
  178. }
  179. FILE* OpenFile(int Fd, const char* Mode) {
  180. return _fdopen(Fd, Mode);
  181. }
  182. int CloseFile(int Fd) {
  183. return _close(Fd);
  184. }
  185. int DuplicateFile(int Fd) {
  186. return _dup(Fd);
  187. }
  188. void RemoveFile(const std::string &Path) {
  189. _unlink(Path.c_str());
  190. }
  191. void RenameFile(const std::string &OldPath, const std::string &NewPath) {
  192. rename(OldPath.c_str(), NewPath.c_str());
  193. }
  194. intptr_t GetHandleFromFd(int fd) {
  195. return _get_osfhandle(fd);
  196. }
  197. bool IsSeparator(char C) {
  198. return C == '\\' || C == '/';
  199. }
  200. // Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
  201. // Returns number of characters considered if successful.
  202. static size_t ParseDrive(const std::string &FileName, const size_t Offset,
  203. bool Relative = true) {
  204. if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':')
  205. return 0;
  206. if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
  207. if (!Relative) // Accept relative path?
  208. return 0;
  209. else
  210. return 2;
  211. }
  212. return 3;
  213. }
  214. // Parse a file name, like: SomeFile.txt
  215. // Returns number of characters considered if successful.
  216. static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
  217. size_t Pos = Offset;
  218. const size_t End = FileName.size();
  219. for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
  220. ;
  221. return Pos - Offset;
  222. }
  223. // Parse a directory ending in separator, like: `SomeDir\`
  224. // Returns number of characters considered if successful.
  225. static size_t ParseDir(const std::string &FileName, const size_t Offset) {
  226. size_t Pos = Offset;
  227. const size_t End = FileName.size();
  228. if (Pos >= End || IsSeparator(FileName[Pos]))
  229. return 0;
  230. for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
  231. ;
  232. if (Pos >= End)
  233. return 0;
  234. ++Pos; // Include separator.
  235. return Pos - Offset;
  236. }
  237. // Parse a servername and share, like: `SomeServer\SomeShare\`
  238. // Returns number of characters considered if successful.
  239. static size_t ParseServerAndShare(const std::string &FileName,
  240. const size_t Offset) {
  241. size_t Pos = Offset, Res;
  242. if (!(Res = ParseDir(FileName, Pos)))
  243. return 0;
  244. Pos += Res;
  245. if (!(Res = ParseDir(FileName, Pos)))
  246. return 0;
  247. Pos += Res;
  248. return Pos - Offset;
  249. }
  250. // Parse the given Ref string from the position Offset, to exactly match the
  251. // given string Patt. Returns number of characters considered if successful.
  252. static size_t ParseCustomString(const std::string &Ref, size_t Offset,
  253. const char *Patt) {
  254. size_t Len = strlen(Patt);
  255. if (Offset + Len > Ref.size())
  256. return 0;
  257. return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
  258. }
  259. // Parse a location, like:
  260. // \\?\UNC\Server\Share\ \\?\C:\ \\Server\Share\ \ C:\ C:
  261. // Returns number of characters considered if successful.
  262. static size_t ParseLocation(const std::string &FileName) {
  263. size_t Pos = 0, Res;
  264. if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
  265. Pos += Res;
  266. if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
  267. Pos += Res;
  268. if ((Res = ParseServerAndShare(FileName, Pos)))
  269. return Pos + Res;
  270. return 0;
  271. }
  272. if ((Res = ParseDrive(FileName, Pos, false)))
  273. return Pos + Res;
  274. return 0;
  275. }
  276. if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
  277. ++Pos;
  278. if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
  279. ++Pos;
  280. if ((Res = ParseServerAndShare(FileName, Pos)))
  281. return Pos + Res;
  282. return 0;
  283. }
  284. return Pos;
  285. }
  286. if ((Res = ParseDrive(FileName, Pos)))
  287. return Pos + Res;
  288. return Pos;
  289. }
  290. std::string DirName(const std::string &FileName) {
  291. size_t LocationLen = ParseLocation(FileName);
  292. size_t DirLen = 0, Res;
  293. while ((Res = ParseDir(FileName, LocationLen + DirLen)))
  294. DirLen += Res;
  295. size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);
  296. if (LocationLen + DirLen + FileLen != FileName.size()) {
  297. Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
  298. exit(1);
  299. }
  300. if (DirLen) {
  301. --DirLen; // Remove trailing separator.
  302. if (!FileLen) { // Path ended in separator.
  303. assert(DirLen);
  304. // Remove file name from Dir.
  305. while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
  306. --DirLen;
  307. if (DirLen) // Remove trailing separator.
  308. --DirLen;
  309. }
  310. }
  311. if (!LocationLen) { // Relative path.
  312. if (!DirLen)
  313. return ".";
  314. return std::string(".\\").append(FileName, 0, DirLen);
  315. }
  316. return FileName.substr(0, LocationLen + DirLen);
  317. }
  318. std::string TmpDir() {
  319. std::string Tmp;
  320. Tmp.resize(MAX_PATH + 1);
  321. DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]);
  322. if (Size == 0) {
  323. Printf("Couldn't get Tmp path.\n");
  324. exit(1);
  325. }
  326. Tmp.resize(Size);
  327. return Tmp;
  328. }
  329. bool IsInterestingCoverageFile(const std::string &FileName) {
  330. if (FileName.find("Program Files") != std::string::npos)
  331. return false;
  332. if (FileName.find("compiler-rt\\lib\\") != std::string::npos)
  333. return false; // sanitizer internal.
  334. if (FileName == "<null>")
  335. return false;
  336. return true;
  337. }
  338. void RawPrint(const char *Str) {
  339. _write(2, Str, strlen(Str));
  340. }
  341. void MkDir(const std::string &Path) {
  342. if (CreateDirectoryA(Path.c_str(), nullptr)) return;
  343. Printf("CreateDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
  344. GetLastError());
  345. }
  346. void RmDir(const std::string &Path) {
  347. if (RemoveDirectoryA(Path.c_str())) return;
  348. Printf("RemoveDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
  349. GetLastError());
  350. }
  351. const std::string &getDevNull() {
  352. static const std::string devNull = "NUL";
  353. return devNull;
  354. }
  355. } // namespace fuzzer
  356. #endif // LIBFUZZER_WINDOWS