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