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