xref: /freebsd/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerIO.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // IO functions.
90b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "FuzzerDefs.h"
120b57cec5SDimitry Andric #include "FuzzerExtFunctions.h"
130b57cec5SDimitry Andric #include "FuzzerIO.h"
140b57cec5SDimitry Andric #include "FuzzerUtil.h"
150b57cec5SDimitry Andric #include <algorithm>
160b57cec5SDimitry Andric #include <cstdarg>
170b57cec5SDimitry Andric #include <fstream>
180b57cec5SDimitry Andric #include <iterator>
190b57cec5SDimitry Andric #include <sys/stat.h>
200b57cec5SDimitry Andric #include <sys/types.h>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace fuzzer {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric static FILE *OutputFile = stderr;
250b57cec5SDimitry Andric 
GetOutputFile()26349cc55cSDimitry Andric FILE *GetOutputFile() {
27349cc55cSDimitry Andric   return OutputFile;
28349cc55cSDimitry Andric }
29349cc55cSDimitry Andric 
SetOutputFile(FILE * NewOutputFile)30349cc55cSDimitry Andric void SetOutputFile(FILE *NewOutputFile) {
31349cc55cSDimitry Andric   OutputFile = NewOutputFile;
32349cc55cSDimitry Andric }
33349cc55cSDimitry Andric 
GetEpoch(const std::string & Path)340b57cec5SDimitry Andric long GetEpoch(const std::string &Path) {
350b57cec5SDimitry Andric   struct stat St;
360b57cec5SDimitry Andric   if (stat(Path.c_str(), &St))
370b57cec5SDimitry Andric     return 0;  // Can't stat, be conservative.
380b57cec5SDimitry Andric   return St.st_mtime;
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
FileToVector(const std::string & Path,size_t MaxSize,bool ExitOnError)410b57cec5SDimitry Andric Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
420b57cec5SDimitry Andric   std::ifstream T(Path, std::ios::binary);
430b57cec5SDimitry Andric   if (ExitOnError && !T) {
440b57cec5SDimitry Andric     Printf("No such directory: %s; exiting\n", Path.c_str());
450b57cec5SDimitry Andric     exit(1);
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   T.seekg(0, T.end);
490b57cec5SDimitry Andric   auto EndPos = T.tellg();
500b57cec5SDimitry Andric   if (EndPos < 0) return {};
510b57cec5SDimitry Andric   size_t FileLen = EndPos;
520b57cec5SDimitry Andric   if (MaxSize)
530b57cec5SDimitry Andric     FileLen = std::min(FileLen, MaxSize);
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   T.seekg(0, T.beg);
560b57cec5SDimitry Andric   Unit Res(FileLen);
570b57cec5SDimitry Andric   T.read(reinterpret_cast<char *>(Res.data()), FileLen);
580b57cec5SDimitry Andric   return Res;
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
FileToString(const std::string & Path)610b57cec5SDimitry Andric std::string FileToString(const std::string &Path) {
620b57cec5SDimitry Andric   std::ifstream T(Path, std::ios::binary);
630b57cec5SDimitry Andric   return std::string((std::istreambuf_iterator<char>(T)),
640b57cec5SDimitry Andric                      std::istreambuf_iterator<char>());
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
CopyFileToErr(const std::string & Path)670b57cec5SDimitry Andric void CopyFileToErr(const std::string &Path) {
68*06c3fb27SDimitry Andric   Puts(FileToString(Path).c_str());
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
WriteToFile(const Unit & U,const std::string & Path)710b57cec5SDimitry Andric void WriteToFile(const Unit &U, const std::string &Path) {
720b57cec5SDimitry Andric   WriteToFile(U.data(), U.size(), Path);
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
WriteToFile(const std::string & Data,const std::string & Path)750b57cec5SDimitry Andric void WriteToFile(const std::string &Data, const std::string &Path) {
760b57cec5SDimitry Andric   WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(),
770b57cec5SDimitry Andric               Path);
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
WriteToFile(const uint8_t * Data,size_t Size,const std::string & Path)800b57cec5SDimitry Andric void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
810b57cec5SDimitry Andric   // Use raw C interface because this function may be called from a sig handler.
820b57cec5SDimitry Andric   FILE *Out = fopen(Path.c_str(), "wb");
830b57cec5SDimitry Andric   if (!Out) return;
840b57cec5SDimitry Andric   fwrite(Data, sizeof(Data[0]), Size, Out);
850b57cec5SDimitry Andric   fclose(Out);
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
AppendToFile(const std::string & Data,const std::string & Path)88e8d8bef9SDimitry Andric void AppendToFile(const std::string &Data, const std::string &Path) {
89e8d8bef9SDimitry Andric   AppendToFile(reinterpret_cast<const uint8_t *>(Data.data()), Data.size(),
90e8d8bef9SDimitry Andric                Path);
91e8d8bef9SDimitry Andric }
92e8d8bef9SDimitry Andric 
AppendToFile(const uint8_t * Data,size_t Size,const std::string & Path)93e8d8bef9SDimitry Andric void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
94e8d8bef9SDimitry Andric   FILE *Out = fopen(Path.c_str(), "a");
95e8d8bef9SDimitry Andric   if (!Out)
96e8d8bef9SDimitry Andric     return;
97e8d8bef9SDimitry Andric   fwrite(Data, sizeof(Data[0]), Size, Out);
98e8d8bef9SDimitry Andric   fclose(Out);
99e8d8bef9SDimitry Andric }
100e8d8bef9SDimitry Andric 
ReadDirToVectorOfUnits(const char * Path,std::vector<Unit> * V,long * Epoch,size_t MaxSize,bool ExitOnError,std::vector<std::string> * VPaths)101349cc55cSDimitry Andric void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, long *Epoch,
102fe6060f1SDimitry Andric                             size_t MaxSize, bool ExitOnError,
103349cc55cSDimitry Andric                             std::vector<std::string> *VPaths) {
1040b57cec5SDimitry Andric   long E = Epoch ? *Epoch : 0;
105349cc55cSDimitry Andric   std::vector<std::string> Files;
1060b57cec5SDimitry Andric   ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
1070b57cec5SDimitry Andric   size_t NumLoaded = 0;
1080b57cec5SDimitry Andric   for (size_t i = 0; i < Files.size(); i++) {
1090b57cec5SDimitry Andric     auto &X = Files[i];
1100b57cec5SDimitry Andric     if (Epoch && GetEpoch(X) < E) continue;
1110b57cec5SDimitry Andric     NumLoaded++;
1120b57cec5SDimitry Andric     if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
1130b57cec5SDimitry Andric       Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
1140b57cec5SDimitry Andric     auto S = FileToVector(X, MaxSize, ExitOnError);
115fe6060f1SDimitry Andric     if (!S.empty()) {
1160b57cec5SDimitry Andric       V->push_back(S);
117fe6060f1SDimitry Andric       if (VPaths)
118fe6060f1SDimitry Andric         VPaths->push_back(X);
1190b57cec5SDimitry Andric     }
1200b57cec5SDimitry Andric   }
121fe6060f1SDimitry Andric }
1220b57cec5SDimitry Andric 
GetSizedFilesFromDir(const std::string & Dir,std::vector<SizedFile> * V)123349cc55cSDimitry Andric void GetSizedFilesFromDir(const std::string &Dir, std::vector<SizedFile> *V) {
124349cc55cSDimitry Andric   std::vector<std::string> Files;
1250b57cec5SDimitry Andric   ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
1260b57cec5SDimitry Andric   for (auto &File : Files)
1270b57cec5SDimitry Andric     if (size_t Size = FileSize(File))
1280b57cec5SDimitry Andric       V->push_back({File, Size});
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
DirPlusFile(const std::string & DirPath,const std::string & FileName)1310b57cec5SDimitry Andric std::string DirPlusFile(const std::string &DirPath,
1320b57cec5SDimitry Andric                         const std::string &FileName) {
1330b57cec5SDimitry Andric   return DirPath + GetSeparator() + FileName;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
DupAndCloseStderr()1360b57cec5SDimitry Andric void DupAndCloseStderr() {
1370b57cec5SDimitry Andric   int OutputFd = DuplicateFile(2);
138480093f4SDimitry Andric   if (OutputFd >= 0) {
1390b57cec5SDimitry Andric     FILE *NewOutputFile = OpenFile(OutputFd, "w");
1400b57cec5SDimitry Andric     if (NewOutputFile) {
1410b57cec5SDimitry Andric       OutputFile = NewOutputFile;
1420b57cec5SDimitry Andric       if (EF->__sanitizer_set_report_fd)
1430b57cec5SDimitry Andric         EF->__sanitizer_set_report_fd(
1440b57cec5SDimitry Andric             reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
1450b57cec5SDimitry Andric       DiscardOutput(2);
1460b57cec5SDimitry Andric     }
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
CloseStdout()1500b57cec5SDimitry Andric void CloseStdout() {
1510b57cec5SDimitry Andric   DiscardOutput(1);
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
Puts(const char * Str)154*06c3fb27SDimitry Andric void Puts(const char *Str) {
155*06c3fb27SDimitry Andric   fputs(Str, OutputFile);
156*06c3fb27SDimitry Andric   fflush(OutputFile);
157*06c3fb27SDimitry Andric }
158*06c3fb27SDimitry Andric 
Printf(const char * Fmt,...)1590b57cec5SDimitry Andric void Printf(const char *Fmt, ...) {
1600b57cec5SDimitry Andric   va_list ap;
1610b57cec5SDimitry Andric   va_start(ap, Fmt);
1620b57cec5SDimitry Andric   vfprintf(OutputFile, Fmt, ap);
1630b57cec5SDimitry Andric   va_end(ap);
1640b57cec5SDimitry Andric   fflush(OutputFile);
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
VPrintf(bool Verbose,const char * Fmt,...)1670b57cec5SDimitry Andric void VPrintf(bool Verbose, const char *Fmt, ...) {
1680b57cec5SDimitry Andric   if (!Verbose) return;
1690b57cec5SDimitry Andric   va_list ap;
1700b57cec5SDimitry Andric   va_start(ap, Fmt);
1710b57cec5SDimitry Andric   vfprintf(OutputFile, Fmt, ap);
1720b57cec5SDimitry Andric   va_end(ap);
1730b57cec5SDimitry Andric   fflush(OutputFile);
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric 
MkDirRecursiveInner(const std::string & Leaf)176e8d8bef9SDimitry Andric static bool MkDirRecursiveInner(const std::string &Leaf) {
177e8d8bef9SDimitry Andric   // Prevent chance of potential infinite recursion
178e8d8bef9SDimitry Andric   if (Leaf == ".")
179e8d8bef9SDimitry Andric     return true;
180e8d8bef9SDimitry Andric 
181e8d8bef9SDimitry Andric   const std::string &Dir = DirName(Leaf);
182e8d8bef9SDimitry Andric 
183e8d8bef9SDimitry Andric   if (IsDirectory(Dir)) {
184e8d8bef9SDimitry Andric     MkDir(Leaf);
185e8d8bef9SDimitry Andric     return IsDirectory(Leaf);
186e8d8bef9SDimitry Andric   }
187e8d8bef9SDimitry Andric 
188e8d8bef9SDimitry Andric   bool ret = MkDirRecursiveInner(Dir);
189e8d8bef9SDimitry Andric   if (!ret) {
190e8d8bef9SDimitry Andric     // Give up early if a previous MkDir failed
191e8d8bef9SDimitry Andric     return ret;
192e8d8bef9SDimitry Andric   }
193e8d8bef9SDimitry Andric 
194e8d8bef9SDimitry Andric   MkDir(Leaf);
195e8d8bef9SDimitry Andric   return IsDirectory(Leaf);
196e8d8bef9SDimitry Andric }
197e8d8bef9SDimitry Andric 
MkDirRecursive(const std::string & Dir)198e8d8bef9SDimitry Andric bool MkDirRecursive(const std::string &Dir) {
199e8d8bef9SDimitry Andric   if (Dir.empty())
200e8d8bef9SDimitry Andric     return false;
201e8d8bef9SDimitry Andric 
202e8d8bef9SDimitry Andric   if (IsDirectory(Dir))
203e8d8bef9SDimitry Andric     return true;
204e8d8bef9SDimitry Andric 
205e8d8bef9SDimitry Andric   return MkDirRecursiveInner(Dir);
206e8d8bef9SDimitry Andric }
207e8d8bef9SDimitry Andric 
RmDirRecursive(const std::string & Dir)2080b57cec5SDimitry Andric void RmDirRecursive(const std::string &Dir) {
2090b57cec5SDimitry Andric   IterateDirRecursive(
2100b57cec5SDimitry Andric       Dir, [](const std::string &Path) {},
2110b57cec5SDimitry Andric       [](const std::string &Path) { RmDir(Path); },
2120b57cec5SDimitry Andric       [](const std::string &Path) { RemoveFile(Path); });
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric 
TempPath(const char * Prefix,const char * Extension)2155ffd83dbSDimitry Andric std::string TempPath(const char *Prefix, const char *Extension) {
2165ffd83dbSDimitry Andric   return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix +
2175ffd83dbSDimitry Andric                                    std::to_string(GetPid()) + Extension);
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric }  // namespace fuzzer
221