// Copied with modifications from CompilerInstance.cpp llvm::raw_fd_ostream* ClangInternalState::createOutputFile(llvm::StringRef OutFile, std::string *TempPathName/*=0*/, bool RemoveFileOnSignal/*=true*/) { std::unique_ptr<llvm::raw_fd_ostream> OS; std::string OSFile; llvm::SmallString<256> OutputPath; llvm::sys::path::system_temp_directory(/*erasedOnReboot*/false, OutputPath); // Only create the temporary if the parent directory exists (or create // missing directories is true) and we can actually write to OutPath, // otherwise we want to fail early. llvm::SmallString<256> TempPath(OutputPath); llvm::sys::fs::make_absolute(TempPath); assert(llvm::sys::fs::is_directory(TempPath.str()) && "Must be a folder."); // Create a temporary file. llvm::sys::path::append(TempPath, "cling-" + OutFile); TempPath += "-" + getCurrentTimeAsString(); TempPath += "-%%%%%%%%"; int fd; if (llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath) != std::errc::no_such_file_or_directory) { OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true)); OSFile = TempPath.str(); } // Make sure the out stream file gets removed if we crash. if (RemoveFileOnSignal) llvm::sys::RemoveFileOnSignal(OSFile); if (TempPathName) *TempPathName = OSFile; return OS.release(); }
String File::TempName(void) { String tempPath = TempPath(); String fileName; do fileName = tempPath + TempPrefix + String::random(16); while(File::Exist(fileName)); return fileName; }
void File::CleanTemp(void) { try { Directory dir(TempPath()); while(dir.nextFile()) try { if(dir.fileName().substr(0,TempPrefix.size()) == TempPrefix) File::Remove(dir.filePath()); } catch(...) { } } catch(const Exception &e) { Log("File::CleanTemp", "Warning: Unable to access temp directory"); } }
int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath, const Vector<SizedFile> &CorporaFiles) { Printf("INFO: collecting data flow: bin: %s dir: %s files: %zd\n", DFTBinary.c_str(), DirPath.c_str(), CorporaFiles.size()); MkDir(DirPath); auto Temp = TempPath(".dft"); for (auto &F : CorporaFiles) { // For every input F we need to collect the data flow and the coverage. // Data flow collection may fail if we request too many DFSan tags at once. // So, we start from requesting all tags in range [0,Size) and if that fails // we then request tags in [0,Size/2) and [Size/2, Size), and so on. // Function number => DFT. std::unordered_map<size_t, Vector<uint8_t>> DFTMap; std::unordered_set<std::string> Cov; std::queue<std::pair<size_t, size_t>> Q; Q.push({0, F.Size}); while (!Q.empty()) { auto R = Q.front(); Printf("\n\n\n********* Trying: [%zd, %zd)\n", R.first, R.second); Q.pop(); Command Cmd; Cmd.addArgument(DFTBinary); Cmd.addArgument(std::to_string(R.first)); Cmd.addArgument(std::to_string(R.second)); Cmd.addArgument(F.File); Cmd.addArgument(Temp); Printf("CMD: %s\n", Cmd.toString().c_str()); if (ExecuteCommand(Cmd)) { // DFSan has failed, collect tags for two subsets. if (R.second - R.first >= 2) { size_t Mid = (R.second + R.first) / 2; Q.push({R.first, Mid}); Q.push({Mid, R.second}); } } else { Printf("********* Success: [%zd, %zd)\n", R.first, R.second); std::ifstream IF(Temp); std::string L; while (std::getline(IF, L, '\n')) { // Data flow collection has succeeded. // Merge the results with the other runs. if (L.empty()) continue; if (L[0] == 'C') { // Take coverage lines as is, they will be the same in all attempts. Cov.insert(L); } else if (L[0] == 'F') { size_t FunctionNum = 0; std::string DFTString; if (ParseDFTLine(L, &FunctionNum, &DFTString)) { auto &DFT = DFTMap[FunctionNum]; if (DFT.empty()) { // Haven't seen this function before, take DFT as is. DFT = DFTStringToVector(DFTString); } else if (DFT.size() == DFTString.size()) { // Have seen this function already, merge DFTs. DFTStringAppendToVector(&DFT, DFTString); } } } } } } auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File))); // Dump combined DFT to disk. Printf("Producing DFT for %s\n", OutPath.c_str()); std::ofstream OF(OutPath); for (auto &DFT: DFTMap) OF << "F" << DFT.first << " " << DFT.second << std::endl; for (auto &C : Cov) OF << C << std::endl; } RemoveFile(Temp); // Write functions.txt. Command Cmd; Cmd.addArgument(DFTBinary); Cmd.setOutputFile(DirPlusFile(DirPath, "functions.txt")); ExecuteCommand(Cmd); return 0; }
FileWriter::FileWriter(const std::string& path) : m_permanentPath(path) , m_tempPath(TempPath(path)) , m_file(new FileIo(m_tempPath, false)) { }