xref: /openbsd-src/gnu/llvm/compiler-rt/lib/fuzzer/FuzzerIO.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick // IO functions.
93cab2bb3Spatrick //===----------------------------------------------------------------------===//
103cab2bb3Spatrick 
113cab2bb3Spatrick #include "FuzzerDefs.h"
123cab2bb3Spatrick #include "FuzzerExtFunctions.h"
133cab2bb3Spatrick #include "FuzzerIO.h"
143cab2bb3Spatrick #include "FuzzerUtil.h"
153cab2bb3Spatrick #include <algorithm>
163cab2bb3Spatrick #include <cstdarg>
173cab2bb3Spatrick #include <fstream>
183cab2bb3Spatrick #include <iterator>
193cab2bb3Spatrick #include <sys/stat.h>
203cab2bb3Spatrick #include <sys/types.h>
213cab2bb3Spatrick 
223cab2bb3Spatrick namespace fuzzer {
233cab2bb3Spatrick 
243cab2bb3Spatrick static FILE *OutputFile = stderr;
253cab2bb3Spatrick 
GetOutputFile()26*810390e3Srobert FILE *GetOutputFile() {
27*810390e3Srobert   return OutputFile;
28*810390e3Srobert }
29*810390e3Srobert 
SetOutputFile(FILE * NewOutputFile)30*810390e3Srobert void SetOutputFile(FILE *NewOutputFile) {
31*810390e3Srobert   OutputFile = NewOutputFile;
32*810390e3Srobert }
33*810390e3Srobert 
GetEpoch(const std::string & Path)343cab2bb3Spatrick long GetEpoch(const std::string &Path) {
353cab2bb3Spatrick   struct stat St;
363cab2bb3Spatrick   if (stat(Path.c_str(), &St))
373cab2bb3Spatrick     return 0;  // Can't stat, be conservative.
383cab2bb3Spatrick   return St.st_mtime;
393cab2bb3Spatrick }
403cab2bb3Spatrick 
FileToVector(const std::string & Path,size_t MaxSize,bool ExitOnError)413cab2bb3Spatrick Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
423cab2bb3Spatrick   std::ifstream T(Path, std::ios::binary);
433cab2bb3Spatrick   if (ExitOnError && !T) {
443cab2bb3Spatrick     Printf("No such directory: %s; exiting\n", Path.c_str());
453cab2bb3Spatrick     exit(1);
463cab2bb3Spatrick   }
473cab2bb3Spatrick 
483cab2bb3Spatrick   T.seekg(0, T.end);
493cab2bb3Spatrick   auto EndPos = T.tellg();
503cab2bb3Spatrick   if (EndPos < 0) return {};
513cab2bb3Spatrick   size_t FileLen = EndPos;
523cab2bb3Spatrick   if (MaxSize)
533cab2bb3Spatrick     FileLen = std::min(FileLen, MaxSize);
543cab2bb3Spatrick 
553cab2bb3Spatrick   T.seekg(0, T.beg);
563cab2bb3Spatrick   Unit Res(FileLen);
573cab2bb3Spatrick   T.read(reinterpret_cast<char *>(Res.data()), FileLen);
583cab2bb3Spatrick   return Res;
593cab2bb3Spatrick }
603cab2bb3Spatrick 
FileToString(const std::string & Path)613cab2bb3Spatrick std::string FileToString(const std::string &Path) {
623cab2bb3Spatrick   std::ifstream T(Path, std::ios::binary);
633cab2bb3Spatrick   return std::string((std::istreambuf_iterator<char>(T)),
643cab2bb3Spatrick                      std::istreambuf_iterator<char>());
653cab2bb3Spatrick }
663cab2bb3Spatrick 
CopyFileToErr(const std::string & Path)673cab2bb3Spatrick void CopyFileToErr(const std::string &Path) {
683cab2bb3Spatrick   Printf("%s", FileToString(Path).c_str());
693cab2bb3Spatrick }
703cab2bb3Spatrick 
WriteToFile(const Unit & U,const std::string & Path)713cab2bb3Spatrick void WriteToFile(const Unit &U, const std::string &Path) {
723cab2bb3Spatrick   WriteToFile(U.data(), U.size(), Path);
733cab2bb3Spatrick }
743cab2bb3Spatrick 
WriteToFile(const std::string & Data,const std::string & Path)753cab2bb3Spatrick void WriteToFile(const std::string &Data, const std::string &Path) {
763cab2bb3Spatrick   WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(),
773cab2bb3Spatrick               Path);
783cab2bb3Spatrick }
793cab2bb3Spatrick 
WriteToFile(const uint8_t * Data,size_t Size,const std::string & Path)803cab2bb3Spatrick void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
813cab2bb3Spatrick   // Use raw C interface because this function may be called from a sig handler.
823cab2bb3Spatrick   FILE *Out = fopen(Path.c_str(), "wb");
833cab2bb3Spatrick   if (!Out) return;
843cab2bb3Spatrick   fwrite(Data, sizeof(Data[0]), Size, Out);
853cab2bb3Spatrick   fclose(Out);
863cab2bb3Spatrick }
873cab2bb3Spatrick 
AppendToFile(const std::string & Data,const std::string & Path)88d89ec533Spatrick void AppendToFile(const std::string &Data, const std::string &Path) {
89d89ec533Spatrick   AppendToFile(reinterpret_cast<const uint8_t *>(Data.data()), Data.size(),
90d89ec533Spatrick                Path);
91d89ec533Spatrick }
92d89ec533Spatrick 
AppendToFile(const uint8_t * Data,size_t Size,const std::string & Path)93d89ec533Spatrick void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
94d89ec533Spatrick   FILE *Out = fopen(Path.c_str(), "a");
95d89ec533Spatrick   if (!Out)
96d89ec533Spatrick     return;
97d89ec533Spatrick   fwrite(Data, sizeof(Data[0]), Size, Out);
98d89ec533Spatrick   fclose(Out);
99d89ec533Spatrick }
100d89ec533Spatrick 
ReadDirToVectorOfUnits(const char * Path,std::vector<Unit> * V,long * Epoch,size_t MaxSize,bool ExitOnError,std::vector<std::string> * VPaths)101*810390e3Srobert void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, long *Epoch,
102d89ec533Spatrick                             size_t MaxSize, bool ExitOnError,
103*810390e3Srobert                             std::vector<std::string> *VPaths) {
1043cab2bb3Spatrick   long E = Epoch ? *Epoch : 0;
105*810390e3Srobert   std::vector<std::string> Files;
1063cab2bb3Spatrick   ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
1073cab2bb3Spatrick   size_t NumLoaded = 0;
1083cab2bb3Spatrick   for (size_t i = 0; i < Files.size(); i++) {
1093cab2bb3Spatrick     auto &X = Files[i];
1103cab2bb3Spatrick     if (Epoch && GetEpoch(X) < E) continue;
1113cab2bb3Spatrick     NumLoaded++;
1123cab2bb3Spatrick     if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
1133cab2bb3Spatrick       Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
1143cab2bb3Spatrick     auto S = FileToVector(X, MaxSize, ExitOnError);
115d89ec533Spatrick     if (!S.empty()) {
1163cab2bb3Spatrick       V->push_back(S);
117d89ec533Spatrick       if (VPaths)
118d89ec533Spatrick         VPaths->push_back(X);
1193cab2bb3Spatrick     }
1203cab2bb3Spatrick   }
121d89ec533Spatrick }
1223cab2bb3Spatrick 
GetSizedFilesFromDir(const std::string & Dir,std::vector<SizedFile> * V)123*810390e3Srobert void GetSizedFilesFromDir(const std::string &Dir, std::vector<SizedFile> *V) {
124*810390e3Srobert   std::vector<std::string> Files;
1253cab2bb3Spatrick   ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
1263cab2bb3Spatrick   for (auto &File : Files)
1273cab2bb3Spatrick     if (size_t Size = FileSize(File))
1283cab2bb3Spatrick       V->push_back({File, Size});
1293cab2bb3Spatrick }
1303cab2bb3Spatrick 
DirPlusFile(const std::string & DirPath,const std::string & FileName)1313cab2bb3Spatrick std::string DirPlusFile(const std::string &DirPath,
1323cab2bb3Spatrick                         const std::string &FileName) {
1333cab2bb3Spatrick   return DirPath + GetSeparator() + FileName;
1343cab2bb3Spatrick }
1353cab2bb3Spatrick 
DupAndCloseStderr()1363cab2bb3Spatrick void DupAndCloseStderr() {
1373cab2bb3Spatrick   int OutputFd = DuplicateFile(2);
1383cab2bb3Spatrick   if (OutputFd >= 0) {
1393cab2bb3Spatrick     FILE *NewOutputFile = OpenFile(OutputFd, "w");
1403cab2bb3Spatrick     if (NewOutputFile) {
1413cab2bb3Spatrick       OutputFile = NewOutputFile;
1423cab2bb3Spatrick       if (EF->__sanitizer_set_report_fd)
1433cab2bb3Spatrick         EF->__sanitizer_set_report_fd(
1443cab2bb3Spatrick             reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
1453cab2bb3Spatrick       DiscardOutput(2);
1463cab2bb3Spatrick     }
1473cab2bb3Spatrick   }
1483cab2bb3Spatrick }
1493cab2bb3Spatrick 
CloseStdout()1503cab2bb3Spatrick void CloseStdout() {
1513cab2bb3Spatrick   DiscardOutput(1);
1523cab2bb3Spatrick }
1533cab2bb3Spatrick 
Printf(const char * Fmt,...)1543cab2bb3Spatrick void Printf(const char *Fmt, ...) {
1553cab2bb3Spatrick   va_list ap;
1563cab2bb3Spatrick   va_start(ap, Fmt);
1573cab2bb3Spatrick   vfprintf(OutputFile, Fmt, ap);
1583cab2bb3Spatrick   va_end(ap);
1593cab2bb3Spatrick   fflush(OutputFile);
1603cab2bb3Spatrick }
1613cab2bb3Spatrick 
VPrintf(bool Verbose,const char * Fmt,...)1623cab2bb3Spatrick void VPrintf(bool Verbose, const char *Fmt, ...) {
1633cab2bb3Spatrick   if (!Verbose) return;
1643cab2bb3Spatrick   va_list ap;
1653cab2bb3Spatrick   va_start(ap, Fmt);
1663cab2bb3Spatrick   vfprintf(OutputFile, Fmt, ap);
1673cab2bb3Spatrick   va_end(ap);
1683cab2bb3Spatrick   fflush(OutputFile);
1693cab2bb3Spatrick }
1703cab2bb3Spatrick 
MkDirRecursiveInner(const std::string & Leaf)171d89ec533Spatrick static bool MkDirRecursiveInner(const std::string &Leaf) {
172d89ec533Spatrick   // Prevent chance of potential infinite recursion
173d89ec533Spatrick   if (Leaf == ".")
174d89ec533Spatrick     return true;
175d89ec533Spatrick 
176d89ec533Spatrick   const std::string &Dir = DirName(Leaf);
177d89ec533Spatrick 
178d89ec533Spatrick   if (IsDirectory(Dir)) {
179d89ec533Spatrick     MkDir(Leaf);
180d89ec533Spatrick     return IsDirectory(Leaf);
181d89ec533Spatrick   }
182d89ec533Spatrick 
183d89ec533Spatrick   bool ret = MkDirRecursiveInner(Dir);
184d89ec533Spatrick   if (!ret) {
185d89ec533Spatrick     // Give up early if a previous MkDir failed
186d89ec533Spatrick     return ret;
187d89ec533Spatrick   }
188d89ec533Spatrick 
189d89ec533Spatrick   MkDir(Leaf);
190d89ec533Spatrick   return IsDirectory(Leaf);
191d89ec533Spatrick }
192d89ec533Spatrick 
MkDirRecursive(const std::string & Dir)193d89ec533Spatrick bool MkDirRecursive(const std::string &Dir) {
194d89ec533Spatrick   if (Dir.empty())
195d89ec533Spatrick     return false;
196d89ec533Spatrick 
197d89ec533Spatrick   if (IsDirectory(Dir))
198d89ec533Spatrick     return true;
199d89ec533Spatrick 
200d89ec533Spatrick   return MkDirRecursiveInner(Dir);
201d89ec533Spatrick }
202d89ec533Spatrick 
RmDirRecursive(const std::string & Dir)2033cab2bb3Spatrick void RmDirRecursive(const std::string &Dir) {
2043cab2bb3Spatrick   IterateDirRecursive(
2053cab2bb3Spatrick       Dir, [](const std::string &Path) {},
2063cab2bb3Spatrick       [](const std::string &Path) { RmDir(Path); },
2073cab2bb3Spatrick       [](const std::string &Path) { RemoveFile(Path); });
2083cab2bb3Spatrick }
2093cab2bb3Spatrick 
TempPath(const char * Prefix,const char * Extension)2101f9cb04fSpatrick std::string TempPath(const char *Prefix, const char *Extension) {
2111f9cb04fSpatrick   return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix +
2121f9cb04fSpatrick                                    std::to_string(GetPid()) + Extension);
2133cab2bb3Spatrick }
2143cab2bb3Spatrick 
2153cab2bb3Spatrick }  // namespace fuzzer
216