Path: blob/main/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerIO.cpp
35262 views
//===- FuzzerIO.cpp - IO utils. -------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7// IO functions.8//===----------------------------------------------------------------------===//910#include "FuzzerDefs.h"11#include "FuzzerExtFunctions.h"12#include "FuzzerIO.h"13#include "FuzzerUtil.h"14#include <algorithm>15#include <cstdarg>16#include <fstream>17#include <iterator>18#include <sys/stat.h>19#include <sys/types.h>2021namespace fuzzer {2223static FILE *OutputFile = stderr;2425FILE *GetOutputFile() {26return OutputFile;27}2829void SetOutputFile(FILE *NewOutputFile) {30OutputFile = NewOutputFile;31}3233long GetEpoch(const std::string &Path) {34struct stat St;35if (stat(Path.c_str(), &St))36return 0; // Can't stat, be conservative.37return St.st_mtime;38}3940Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {41std::ifstream T(Path, std::ios::binary);42if (ExitOnError && !T) {43Printf("No such directory: %s; exiting\n", Path.c_str());44exit(1);45}4647T.seekg(0, T.end);48auto EndPos = T.tellg();49if (EndPos < 0) return {};50size_t FileLen = EndPos;51if (MaxSize)52FileLen = std::min(FileLen, MaxSize);5354T.seekg(0, T.beg);55Unit Res(FileLen);56T.read(reinterpret_cast<char *>(Res.data()), FileLen);57return Res;58}5960std::string FileToString(const std::string &Path) {61std::ifstream T(Path, std::ios::binary);62return std::string((std::istreambuf_iterator<char>(T)),63std::istreambuf_iterator<char>());64}6566void CopyFileToErr(const std::string &Path) {67Puts(FileToString(Path).c_str());68}6970void WriteToFile(const Unit &U, const std::string &Path) {71WriteToFile(U.data(), U.size(), Path);72}7374void WriteToFile(const std::string &Data, const std::string &Path) {75WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(),76Path);77}7879void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) {80// Use raw C interface because this function may be called from a sig handler.81FILE *Out = fopen(Path.c_str(), "wb");82if (!Out) return;83fwrite(Data, sizeof(Data[0]), Size, Out);84fclose(Out);85}8687void AppendToFile(const std::string &Data, const std::string &Path) {88AppendToFile(reinterpret_cast<const uint8_t *>(Data.data()), Data.size(),89Path);90}9192void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) {93FILE *Out = fopen(Path.c_str(), "a");94if (!Out)95return;96fwrite(Data, sizeof(Data[0]), Size, Out);97fclose(Out);98}99100void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, long *Epoch,101size_t MaxSize, bool ExitOnError,102std::vector<std::string> *VPaths) {103long E = Epoch ? *Epoch : 0;104std::vector<std::string> Files;105ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);106size_t NumLoaded = 0;107for (size_t i = 0; i < Files.size(); i++) {108auto &X = Files[i];109if (Epoch && GetEpoch(X) < E) continue;110NumLoaded++;111if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)112Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);113auto S = FileToVector(X, MaxSize, ExitOnError);114if (!S.empty()) {115V->push_back(S);116if (VPaths)117VPaths->push_back(X);118}119}120}121122void GetSizedFilesFromDir(const std::string &Dir, std::vector<SizedFile> *V) {123std::vector<std::string> Files;124ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);125for (auto &File : Files)126if (size_t Size = FileSize(File))127V->push_back({File, Size});128}129130std::string DirPlusFile(const std::string &DirPath,131const std::string &FileName) {132return DirPath + GetSeparator() + FileName;133}134135void DupAndCloseStderr() {136int OutputFd = DuplicateFile(2);137if (OutputFd >= 0) {138FILE *NewOutputFile = OpenFile(OutputFd, "w");139if (NewOutputFile) {140OutputFile = NewOutputFile;141if (EF->__sanitizer_set_report_fd)142EF->__sanitizer_set_report_fd(143reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));144DiscardOutput(2);145}146}147}148149void CloseStdout() {150DiscardOutput(1);151}152153void Puts(const char *Str) {154fputs(Str, OutputFile);155fflush(OutputFile);156}157158void Printf(const char *Fmt, ...) {159va_list ap;160va_start(ap, Fmt);161vfprintf(OutputFile, Fmt, ap);162va_end(ap);163fflush(OutputFile);164}165166void VPrintf(bool Verbose, const char *Fmt, ...) {167if (!Verbose) return;168va_list ap;169va_start(ap, Fmt);170vfprintf(OutputFile, Fmt, ap);171va_end(ap);172fflush(OutputFile);173}174175static bool MkDirRecursiveInner(const std::string &Leaf) {176// Prevent chance of potential infinite recursion177if (Leaf == ".")178return true;179180const std::string &Dir = DirName(Leaf);181182if (IsDirectory(Dir)) {183MkDir(Leaf);184return IsDirectory(Leaf);185}186187bool ret = MkDirRecursiveInner(Dir);188if (!ret) {189// Give up early if a previous MkDir failed190return ret;191}192193MkDir(Leaf);194return IsDirectory(Leaf);195}196197bool MkDirRecursive(const std::string &Dir) {198if (Dir.empty())199return false;200201if (IsDirectory(Dir))202return true;203204return MkDirRecursiveInner(Dir);205}206207void RmDirRecursive(const std::string &Dir) {208IterateDirRecursive(209Dir, [](const std::string &Path) {},210[](const std::string &Path) { RmDir(Path); },211[](const std::string &Path) { RemoveFile(Path); });212}213214std::string TempPath(const char *Prefix, const char *Extension) {215return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix +216std::to_string(GetPid()) + Extension);217}218219} // namespace fuzzer220221222