FuzzerIO.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
  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.
  9. //===----------------------------------------------------------------------===//
  10. #include "FuzzerDefs.h"
  11. #include "FuzzerExtFunctions.h"
  12. #include "FuzzerIO.h"
  13. #include "FuzzerUtil.h"
  14. #include <algorithm>
  15. #include <cstdarg>
  16. #include <fstream>
  17. #include <iterator>
  18. #include <sys/stat.h>
  19. #include <sys/types.h>
  20. namespace fuzzer {
  21. static FILE *OutputFile = stderr;
  22. FILE *GetOutputFile() {
  23. return OutputFile;
  24. }
  25. void SetOutputFile(FILE *NewOutputFile) {
  26. OutputFile = NewOutputFile;
  27. }
  28. long GetEpoch(const std::string &Path) {
  29. struct stat St;
  30. if (stat(Path.c_str(), &St))
  31. return 0; // Can't stat, be conservative.
  32. return St.st_mtime;
  33. }
  34. Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
  35. std::ifstream T(Path, std::ios::binary);
  36. if (ExitOnError && !T) {
  37. Printf("No such directory: %s; exiting\n", Path.c_str());
  38. exit(1);
  39. }
  40. T.seekg(0, T.end);
  41. auto EndPos = T.tellg();
  42. if (EndPos < 0) return {};
  43. size_t FileLen = EndPos;
  44. if (MaxSize)
  45. FileLen = std::min(FileLen, MaxSize);
  46. T.seekg(0, T.beg);
  47. Unit Res(FileLen);
  48. T.read(reinterpret_cast<char *>(Res.data()), FileLen);
  49. return Res;
  50. }
  51. std::string FileToString(const std::string &Path) {
  52. std::ifstream T(Path, std::ios::binary);
  53. return std::string((std::istreambuf_iterator<char>(T)),
  54. std::istreambuf_iterator<char>());
  55. }
  56. void CopyFileToErr(const std::string &Path) {
  57. Printf("%s", FileToString(Path).c_str());
  58. }
  59. void WriteToFile(const Unit &U, const std::string &Path) {
  60. WriteToFile(U.data(), U.size(), Path);
  61. }
  62. void WriteToFile(const std::string &Data, const std::string &Path) {
  63. WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(),
  64. Path);
  65. }
  66. void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
  67. // Use raw C interface because this function may be called from a sig handler.
  68. FILE *Out = fopen(Path.c_str(), "wb");
  69. if (!Out) return;
  70. fwrite(Data, sizeof(Data[0]), Size, Out);
  71. fclose(Out);
  72. }
  73. void AppendToFile(const std::string &Data, const std::string &Path) {
  74. AppendToFile(reinterpret_cast<const uint8_t *>(Data.data()), Data.size(),
  75. Path);
  76. }
  77. void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
  78. FILE *Out = fopen(Path.c_str(), "a");
  79. if (!Out)
  80. return;
  81. fwrite(Data, sizeof(Data[0]), Size, Out);
  82. fclose(Out);
  83. }
  84. void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, long *Epoch,
  85. size_t MaxSize, bool ExitOnError,
  86. std::vector<std::string> *VPaths) {
  87. long E = Epoch ? *Epoch : 0;
  88. std::vector<std::string> Files;
  89. ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
  90. size_t NumLoaded = 0;
  91. for (size_t i = 0; i < Files.size(); i++) {
  92. auto &X = Files[i];
  93. if (Epoch && GetEpoch(X) < E) continue;
  94. NumLoaded++;
  95. if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
  96. Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
  97. auto S = FileToVector(X, MaxSize, ExitOnError);
  98. if (!S.empty()) {
  99. V->push_back(S);
  100. if (VPaths)
  101. VPaths->push_back(X);
  102. }
  103. }
  104. }
  105. void GetSizedFilesFromDir(const std::string &Dir, std::vector<SizedFile> *V) {
  106. std::vector<std::string> Files;
  107. ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
  108. for (auto &File : Files)
  109. if (size_t Size = FileSize(File))
  110. V->push_back({File, Size});
  111. }
  112. std::string DirPlusFile(const std::string &DirPath,
  113. const std::string &FileName) {
  114. return DirPath + GetSeparator() + FileName;
  115. }
  116. void DupAndCloseStderr() {
  117. int OutputFd = DuplicateFile(2);
  118. if (OutputFd >= 0) {
  119. FILE *NewOutputFile = OpenFile(OutputFd, "w");
  120. if (NewOutputFile) {
  121. OutputFile = NewOutputFile;
  122. if (EF->__sanitizer_set_report_fd)
  123. EF->__sanitizer_set_report_fd(
  124. reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
  125. DiscardOutput(2);
  126. }
  127. }
  128. }
  129. void CloseStdout() {
  130. DiscardOutput(1);
  131. }
  132. void Printf(const char *Fmt, ...) {
  133. va_list ap;
  134. va_start(ap, Fmt);
  135. vfprintf(OutputFile, Fmt, ap);
  136. va_end(ap);
  137. fflush(OutputFile);
  138. }
  139. void VPrintf(bool Verbose, const char *Fmt, ...) {
  140. if (!Verbose) return;
  141. va_list ap;
  142. va_start(ap, Fmt);
  143. vfprintf(OutputFile, Fmt, ap);
  144. va_end(ap);
  145. fflush(OutputFile);
  146. }
  147. static bool MkDirRecursiveInner(const std::string &Leaf) {
  148. // Prevent chance of potential infinite recursion
  149. if (Leaf == ".")
  150. return true;
  151. const std::string &Dir = DirName(Leaf);
  152. if (IsDirectory(Dir)) {
  153. MkDir(Leaf);
  154. return IsDirectory(Leaf);
  155. }
  156. bool ret = MkDirRecursiveInner(Dir);
  157. if (!ret) {
  158. // Give up early if a previous MkDir failed
  159. return ret;
  160. }
  161. MkDir(Leaf);
  162. return IsDirectory(Leaf);
  163. }
  164. bool MkDirRecursive(const std::string &Dir) {
  165. if (Dir.empty())
  166. return false;
  167. if (IsDirectory(Dir))
  168. return true;
  169. return MkDirRecursiveInner(Dir);
  170. }
  171. void RmDirRecursive(const std::string &Dir) {
  172. IterateDirRecursive(
  173. Dir, [](const std::string &Path) {},
  174. [](const std::string &Path) { RmDir(Path); },
  175. [](const std::string &Path) { RemoveFile(Path); });
  176. }
  177. std::string TempPath(const char *Prefix, const char *Extension) {
  178. return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix +
  179. std::to_string(GetPid()) + Extension);
  180. }
  181. } // namespace fuzzer