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