xref: /llvm-project/compiler-rt/lib/fuzzer/FuzzerIO.cpp (revision 90b4d1bcb20180c591385131b12fa90d2e4860b1)
110ab2aceSGeorge Karpenkov //===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // IO functions.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1010ab2aceSGeorge Karpenkov 
1110ab2aceSGeorge Karpenkov #include "FuzzerDefs.h"
1210ab2aceSGeorge Karpenkov #include "FuzzerExtFunctions.h"
135c08e811SKostya Serebryany #include "FuzzerIO.h"
145c08e811SKostya Serebryany #include "FuzzerUtil.h"
1510ab2aceSGeorge Karpenkov #include <algorithm>
1610ab2aceSGeorge Karpenkov #include <cstdarg>
1710ab2aceSGeorge Karpenkov #include <fstream>
1810ab2aceSGeorge Karpenkov #include <iterator>
1910ab2aceSGeorge Karpenkov #include <sys/stat.h>
2010ab2aceSGeorge Karpenkov #include <sys/types.h>
2110ab2aceSGeorge Karpenkov 
2210ab2aceSGeorge Karpenkov namespace fuzzer {
2310ab2aceSGeorge Karpenkov 
2410ab2aceSGeorge Karpenkov static FILE *OutputFile = stderr;
2510ab2aceSGeorge Karpenkov 
GetOutputFile()26c7bd6435SHans Wennborg FILE *GetOutputFile() {
27c7bd6435SHans Wennborg   return OutputFile;
28c7bd6435SHans Wennborg }
29c7bd6435SHans Wennborg 
SetOutputFile(FILE * NewOutputFile)30c7bd6435SHans Wennborg void SetOutputFile(FILE *NewOutputFile) {
31c7bd6435SHans Wennborg   OutputFile = NewOutputFile;
32c7bd6435SHans Wennborg }
33c7bd6435SHans Wennborg 
GetEpoch(const std::string & Path)3410ab2aceSGeorge Karpenkov long GetEpoch(const std::string &Path) {
3510ab2aceSGeorge Karpenkov   struct stat St;
3610ab2aceSGeorge Karpenkov   if (stat(Path.c_str(), &St))
3710ab2aceSGeorge Karpenkov     return 0;  // Can't stat, be conservative.
3810ab2aceSGeorge Karpenkov   return St.st_mtime;
3910ab2aceSGeorge Karpenkov }
4010ab2aceSGeorge Karpenkov 
FileToVector(const std::string & Path,size_t MaxSize,bool ExitOnError)4110ab2aceSGeorge Karpenkov Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
4239b6ba9fSJonathan Metzman   std::ifstream T(Path, std::ios::binary);
4310ab2aceSGeorge Karpenkov   if (ExitOnError && !T) {
4410ab2aceSGeorge Karpenkov     Printf("No such directory: %s; exiting\n", Path.c_str());
4510ab2aceSGeorge Karpenkov     exit(1);
4610ab2aceSGeorge Karpenkov   }
4710ab2aceSGeorge Karpenkov 
4810ab2aceSGeorge Karpenkov   T.seekg(0, T.end);
4910ab2aceSGeorge Karpenkov   auto EndPos = T.tellg();
5010ab2aceSGeorge Karpenkov   if (EndPos < 0) return {};
5110ab2aceSGeorge Karpenkov   size_t FileLen = EndPos;
5210ab2aceSGeorge Karpenkov   if (MaxSize)
5310ab2aceSGeorge Karpenkov     FileLen = std::min(FileLen, MaxSize);
5410ab2aceSGeorge Karpenkov 
5510ab2aceSGeorge Karpenkov   T.seekg(0, T.beg);
5610ab2aceSGeorge Karpenkov   Unit Res(FileLen);
5710ab2aceSGeorge Karpenkov   T.read(reinterpret_cast<char *>(Res.data()), FileLen);
5810ab2aceSGeorge Karpenkov   return Res;
5910ab2aceSGeorge Karpenkov }
6010ab2aceSGeorge Karpenkov 
FileToString(const std::string & Path)6110ab2aceSGeorge Karpenkov std::string FileToString(const std::string &Path) {
6239b6ba9fSJonathan Metzman   std::ifstream T(Path, std::ios::binary);
6310ab2aceSGeorge Karpenkov   return std::string((std::istreambuf_iterator<char>(T)),
6410ab2aceSGeorge Karpenkov                      std::istreambuf_iterator<char>());
6510ab2aceSGeorge Karpenkov }
6610ab2aceSGeorge Karpenkov 
CopyFileToErr(const std::string & Path)6710ab2aceSGeorge Karpenkov void CopyFileToErr(const std::string &Path) {
68*90b4d1bcSRoy Sundahl   Puts(FileToString(Path).c_str());
6910ab2aceSGeorge Karpenkov }
7010ab2aceSGeorge Karpenkov 
WriteToFile(const Unit & U,const std::string & Path)7110ab2aceSGeorge Karpenkov void WriteToFile(const Unit &U, const std::string &Path) {
724614cc3dSKostya Serebryany   WriteToFile(U.data(), U.size(), Path);
734614cc3dSKostya Serebryany }
744614cc3dSKostya Serebryany 
WriteToFile(const std::string & Data,const std::string & Path)75f3ee9773SJonathan Metzman void WriteToFile(const std::string &Data, const std::string &Path) {
76f3ee9773SJonathan Metzman   WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(),
77f3ee9773SJonathan Metzman               Path);
78f3ee9773SJonathan Metzman }
79f3ee9773SJonathan Metzman 
WriteToFile(const uint8_t * Data,size_t Size,const std::string & Path)804614cc3dSKostya Serebryany void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
8110ab2aceSGeorge Karpenkov   // Use raw C interface because this function may be called from a sig handler.
823db6ad2bSVitaly Buka   FILE *Out = fopen(Path.c_str(), "wb");
8310ab2aceSGeorge Karpenkov   if (!Out) return;
844614cc3dSKostya Serebryany   fwrite(Data, sizeof(Data[0]), Size, Out);
8510ab2aceSGeorge Karpenkov   fclose(Out);
8610ab2aceSGeorge Karpenkov }
8710ab2aceSGeorge Karpenkov 
AppendToFile(const std::string & Data,const std::string & Path)881bb1eac6SDokyung Song void AppendToFile(const std::string &Data, const std::string &Path) {
891bb1eac6SDokyung Song   AppendToFile(reinterpret_cast<const uint8_t *>(Data.data()), Data.size(),
901bb1eac6SDokyung Song                Path);
911bb1eac6SDokyung Song }
921bb1eac6SDokyung Song 
AppendToFile(const uint8_t * Data,size_t Size,const std::string & Path)931bb1eac6SDokyung Song void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) {
941bb1eac6SDokyung Song   FILE *Out = fopen(Path.c_str(), "a");
951bb1eac6SDokyung Song   if (!Out)
961bb1eac6SDokyung Song     return;
971bb1eac6SDokyung Song   fwrite(Data, sizeof(Data[0]), Size, Out);
981bb1eac6SDokyung Song   fclose(Out);
991bb1eac6SDokyung Song }
1001bb1eac6SDokyung Song 
ReadDirToVectorOfUnits(const char * Path,std::vector<Unit> * V,long * Epoch,size_t MaxSize,bool ExitOnError,std::vector<std::string> * VPaths)1017c921753SKostya Serebryany void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, long *Epoch,
102827ccc93SAlexey Vishnyakov                             size_t MaxSize, bool ExitOnError,
1037c921753SKostya Serebryany                             std::vector<std::string> *VPaths) {
10410ab2aceSGeorge Karpenkov   long E = Epoch ? *Epoch : 0;
1057c921753SKostya Serebryany   std::vector<std::string> Files;
10610ab2aceSGeorge Karpenkov   ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
10710ab2aceSGeorge Karpenkov   size_t NumLoaded = 0;
10810ab2aceSGeorge Karpenkov   for (size_t i = 0; i < Files.size(); i++) {
10910ab2aceSGeorge Karpenkov     auto &X = Files[i];
11010ab2aceSGeorge Karpenkov     if (Epoch && GetEpoch(X) < E) continue;
11110ab2aceSGeorge Karpenkov     NumLoaded++;
11210ab2aceSGeorge Karpenkov     if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
11310ab2aceSGeorge Karpenkov       Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
11410ab2aceSGeorge Karpenkov     auto S = FileToVector(X, MaxSize, ExitOnError);
115827ccc93SAlexey Vishnyakov     if (!S.empty()) {
11610ab2aceSGeorge Karpenkov       V->push_back(S);
117827ccc93SAlexey Vishnyakov       if (VPaths)
118827ccc93SAlexey Vishnyakov         VPaths->push_back(X);
11910ab2aceSGeorge Karpenkov     }
12010ab2aceSGeorge Karpenkov   }
121827ccc93SAlexey Vishnyakov }
12293679be0SKostya Serebryany 
GetSizedFilesFromDir(const std::string & Dir,std::vector<SizedFile> * V)1237c921753SKostya Serebryany void GetSizedFilesFromDir(const std::string &Dir, std::vector<SizedFile> *V) {
1247c921753SKostya Serebryany   std::vector<std::string> Files;
12593679be0SKostya Serebryany   ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
12693679be0SKostya Serebryany   for (auto &File : Files)
12793679be0SKostya Serebryany     if (size_t Size = FileSize(File))
12893679be0SKostya Serebryany       V->push_back({File, Size});
12993679be0SKostya Serebryany }
13093679be0SKostya Serebryany 
DirPlusFile(const std::string & DirPath,const std::string & FileName)13110ab2aceSGeorge Karpenkov std::string DirPlusFile(const std::string &DirPath,
13210ab2aceSGeorge Karpenkov                         const std::string &FileName) {
13310ab2aceSGeorge Karpenkov   return DirPath + GetSeparator() + FileName;
13410ab2aceSGeorge Karpenkov }
13510ab2aceSGeorge Karpenkov 
DupAndCloseStderr()13610ab2aceSGeorge Karpenkov void DupAndCloseStderr() {
13710ab2aceSGeorge Karpenkov   int OutputFd = DuplicateFile(2);
13816d9f44fSMarco Vanotti   if (OutputFd >= 0) {
13910ab2aceSGeorge Karpenkov     FILE *NewOutputFile = OpenFile(OutputFd, "w");
14010ab2aceSGeorge Karpenkov     if (NewOutputFile) {
14110ab2aceSGeorge Karpenkov       OutputFile = NewOutputFile;
14210ab2aceSGeorge Karpenkov       if (EF->__sanitizer_set_report_fd)
14310ab2aceSGeorge Karpenkov         EF->__sanitizer_set_report_fd(
14410ab2aceSGeorge Karpenkov             reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
14510ab2aceSGeorge Karpenkov       DiscardOutput(2);
14610ab2aceSGeorge Karpenkov     }
14710ab2aceSGeorge Karpenkov   }
14810ab2aceSGeorge Karpenkov }
14910ab2aceSGeorge Karpenkov 
CloseStdout()15010ab2aceSGeorge Karpenkov void CloseStdout() {
15110ab2aceSGeorge Karpenkov   DiscardOutput(1);
15210ab2aceSGeorge Karpenkov }
15310ab2aceSGeorge Karpenkov 
Puts(const char * Str)154*90b4d1bcSRoy Sundahl void Puts(const char *Str) {
155*90b4d1bcSRoy Sundahl   fputs(Str, OutputFile);
156*90b4d1bcSRoy Sundahl   fflush(OutputFile);
157*90b4d1bcSRoy Sundahl }
158*90b4d1bcSRoy Sundahl 
Printf(const char * Fmt,...)15910ab2aceSGeorge Karpenkov void Printf(const char *Fmt, ...) {
16010ab2aceSGeorge Karpenkov   va_list ap;
16110ab2aceSGeorge Karpenkov   va_start(ap, Fmt);
16210ab2aceSGeorge Karpenkov   vfprintf(OutputFile, Fmt, ap);
16310ab2aceSGeorge Karpenkov   va_end(ap);
16410ab2aceSGeorge Karpenkov   fflush(OutputFile);
16510ab2aceSGeorge Karpenkov }
16610ab2aceSGeorge Karpenkov 
VPrintf(bool Verbose,const char * Fmt,...)1672b9a8f37SKostya Serebryany void VPrintf(bool Verbose, const char *Fmt, ...) {
1682b9a8f37SKostya Serebryany   if (!Verbose) return;
1692b9a8f37SKostya Serebryany   va_list ap;
1702b9a8f37SKostya Serebryany   va_start(ap, Fmt);
1712b9a8f37SKostya Serebryany   vfprintf(OutputFile, Fmt, ap);
1722b9a8f37SKostya Serebryany   va_end(ap);
1732b9a8f37SKostya Serebryany   fflush(OutputFile);
1742b9a8f37SKostya Serebryany }
1752b9a8f37SKostya Serebryany 
MkDirRecursiveInner(const std::string & Leaf)176711b9806SMatt Morehouse static bool MkDirRecursiveInner(const std::string &Leaf) {
177711b9806SMatt Morehouse   // Prevent chance of potential infinite recursion
178711b9806SMatt Morehouse   if (Leaf == ".")
179711b9806SMatt Morehouse     return true;
180711b9806SMatt Morehouse 
181711b9806SMatt Morehouse   const std::string &Dir = DirName(Leaf);
182711b9806SMatt Morehouse 
183711b9806SMatt Morehouse   if (IsDirectory(Dir)) {
184711b9806SMatt Morehouse     MkDir(Leaf);
185711b9806SMatt Morehouse     return IsDirectory(Leaf);
186711b9806SMatt Morehouse   }
187711b9806SMatt Morehouse 
188711b9806SMatt Morehouse   bool ret = MkDirRecursiveInner(Dir);
189711b9806SMatt Morehouse   if (!ret) {
190711b9806SMatt Morehouse     // Give up early if a previous MkDir failed
191711b9806SMatt Morehouse     return ret;
192711b9806SMatt Morehouse   }
193711b9806SMatt Morehouse 
194711b9806SMatt Morehouse   MkDir(Leaf);
195711b9806SMatt Morehouse   return IsDirectory(Leaf);
196711b9806SMatt Morehouse }
197711b9806SMatt Morehouse 
MkDirRecursive(const std::string & Dir)198711b9806SMatt Morehouse bool MkDirRecursive(const std::string &Dir) {
199711b9806SMatt Morehouse   if (Dir.empty())
200711b9806SMatt Morehouse     return false;
201711b9806SMatt Morehouse 
202711b9806SMatt Morehouse   if (IsDirectory(Dir))
203711b9806SMatt Morehouse     return true;
204711b9806SMatt Morehouse 
205711b9806SMatt Morehouse   return MkDirRecursiveInner(Dir);
206711b9806SMatt Morehouse }
207711b9806SMatt Morehouse 
RmDirRecursive(const std::string & Dir)208d0857484SKostya Serebryany void RmDirRecursive(const std::string &Dir) {
2099982ee54SKostya Serebryany   IterateDirRecursive(
210d0857484SKostya Serebryany       Dir, [](const std::string &Path) {},
211d0857484SKostya Serebryany       [](const std::string &Path) { RmDir(Path); },
212d0857484SKostya Serebryany       [](const std::string &Path) { RemoveFile(Path); });
21363f48717SKostya Serebryany }
21463f48717SKostya Serebryany 
TempPath(const char * Prefix,const char * Extension)2154f3c3bbbSYuanfang Chen std::string TempPath(const char *Prefix, const char *Extension) {
2164f3c3bbbSYuanfang Chen   return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix +
2174f3c3bbbSYuanfang Chen                                    std::to_string(GetPid()) + Extension);
2185c08e811SKostya Serebryany }
2195c08e811SKostya Serebryany 
22010ab2aceSGeorge Karpenkov }  // namespace fuzzer
221