1 //===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 //===----------------------------------------------------------------------===//
11 #include "FuzzerDefs.h"
12 #include "FuzzerExtFunctions.h"
14 #include "FuzzerUtil.h"
20 #include <sys/types.h>
24 static FILE *OutputFile
= stderr
;
26 FILE *GetOutputFile() {
30 void SetOutputFile(FILE *NewOutputFile
) {
31 OutputFile
= NewOutputFile
;
34 long GetEpoch(const std::string
&Path
) {
36 if (stat(Path
.c_str(), &St
))
37 return 0; // Can't stat, be conservative.
41 Unit
FileToVector(const std::string
&Path
, size_t MaxSize
, bool ExitOnError
) {
42 std::ifstream
T(Path
, std::ios::binary
);
43 if (ExitOnError
&& !T
) {
44 Printf("No such directory: %s; exiting\n", Path
.c_str());
49 auto EndPos
= T
.tellg();
50 if (EndPos
< 0) return {};
51 size_t FileLen
= EndPos
;
53 FileLen
= std::min(FileLen
, MaxSize
);
57 T
.read(reinterpret_cast<char *>(Res
.data()), FileLen
);
61 std::string
FileToString(const std::string
&Path
) {
62 std::ifstream
T(Path
, std::ios::binary
);
63 return std::string((std::istreambuf_iterator
<char>(T
)),
64 std::istreambuf_iterator
<char>());
67 void CopyFileToErr(const std::string
&Path
) {
68 Puts(FileToString(Path
).c_str());
71 void WriteToFile(const Unit
&U
, const std::string
&Path
) {
72 WriteToFile(U
.data(), U
.size(), Path
);
75 void WriteToFile(const std::string
&Data
, const std::string
&Path
) {
76 WriteToFile(reinterpret_cast<const uint8_t *>(Data
.c_str()), Data
.size(),
80 void WriteToFile(const uint8_t *Data
, size_t Size
, const std::string
&Path
) {
81 // Use raw C interface because this function may be called from a sig handler.
82 FILE *Out
= fopen(Path
.c_str(), "wb");
84 fwrite(Data
, sizeof(Data
[0]), Size
, Out
);
88 void AppendToFile(const std::string
&Data
, const std::string
&Path
) {
89 AppendToFile(reinterpret_cast<const uint8_t *>(Data
.data()), Data
.size(),
93 void AppendToFile(const uint8_t *Data
, size_t Size
, const std::string
&Path
) {
94 FILE *Out
= fopen(Path
.c_str(), "a");
97 fwrite(Data
, sizeof(Data
[0]), Size
, Out
);
101 void ReadDirToVectorOfUnits(const char *Path
, std::vector
<Unit
> *V
, long *Epoch
,
102 size_t MaxSize
, bool ExitOnError
,
103 std::vector
<std::string
> *VPaths
) {
104 long E
= Epoch
? *Epoch
: 0;
105 std::vector
<std::string
> Files
;
106 ListFilesInDirRecursive(Path
, Epoch
, &Files
, /*TopDir*/true);
107 size_t NumLoaded
= 0;
108 for (size_t i
= 0; i
< Files
.size(); i
++) {
110 if (Epoch
&& GetEpoch(X
) < E
) continue;
112 if ((NumLoaded
& (NumLoaded
- 1)) == 0 && NumLoaded
>= 1024)
113 Printf("Loaded %zd/%zd files from %s\n", NumLoaded
, Files
.size(), Path
);
114 auto S
= FileToVector(X
, MaxSize
, ExitOnError
);
118 VPaths
->push_back(X
);
123 void GetSizedFilesFromDir(const std::string
&Dir
, std::vector
<SizedFile
> *V
) {
124 std::vector
<std::string
> Files
;
125 ListFilesInDirRecursive(Dir
, 0, &Files
, /*TopDir*/true);
126 for (auto &File
: Files
)
127 if (size_t Size
= FileSize(File
))
128 V
->push_back({File
, Size
});
131 std::string
DirPlusFile(const std::string
&DirPath
,
132 const std::string
&FileName
) {
133 return DirPath
+ GetSeparator() + FileName
;
136 void DupAndCloseStderr() {
137 int OutputFd
= DuplicateFile(2);
139 FILE *NewOutputFile
= OpenFile(OutputFd
, "w");
141 OutputFile
= NewOutputFile
;
142 if (EF
->__sanitizer_set_report_fd
)
143 EF
->__sanitizer_set_report_fd(
144 reinterpret_cast<void *>(GetHandleFromFd(OutputFd
)));
154 void Puts(const char *Str
) {
155 fputs(Str
, OutputFile
);
159 void Printf(const char *Fmt
, ...) {
162 vfprintf(OutputFile
, Fmt
, ap
);
167 void VPrintf(bool Verbose
, const char *Fmt
, ...) {
168 if (!Verbose
) return;
171 vfprintf(OutputFile
, Fmt
, ap
);
176 static bool MkDirRecursiveInner(const std::string
&Leaf
) {
177 // Prevent chance of potential infinite recursion
181 const std::string
&Dir
= DirName(Leaf
);
183 if (IsDirectory(Dir
)) {
185 return IsDirectory(Leaf
);
188 bool ret
= MkDirRecursiveInner(Dir
);
190 // Give up early if a previous MkDir failed
195 return IsDirectory(Leaf
);
198 bool MkDirRecursive(const std::string
&Dir
) {
202 if (IsDirectory(Dir
))
205 return MkDirRecursiveInner(Dir
);
208 void RmDirRecursive(const std::string
&Dir
) {
210 Dir
, [](const std::string
&Path
) {},
211 [](const std::string
&Path
) { RmDir(Path
); },
212 [](const std::string
&Path
) { RemoveFile(Path
); });
215 std::string
TempPath(const char *Prefix
, const char *Extension
) {
216 return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix
+
217 std::to_string(GetPid()) + Extension
);
220 } // namespace fuzzer