Revert r363326 "[libFuzzer] simplify the DFT trace collection using the new faster DFSan mode that traces up to 16 labels at a time and never runs out of labels."
It broke the Windows build:
C:\b\s\w\ir\cache\builder\src\third_party\llvm\compiler-rt\lib\fuzzer\FuzzerDataFlowTrace.cpp(243): error C3861: 'setenv': identifier not found
This also reverts the follow-up r363327.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer@363358 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/FuzzerDataFlowTrace.cpp b/FuzzerDataFlowTrace.cpp
index 311f53a..1fba391 100644
--- a/FuzzerDataFlowTrace.cpp
+++ b/FuzzerDataFlowTrace.cpp
@@ -120,6 +120,12 @@
return DFT;
}
+static std::ostream &operator<<(std::ostream &OS, const Vector<uint8_t> &DFT) {
+ for (auto B : DFT)
+ OS << (B ? "1" : "0");
+ return OS;
+}
+
static bool ParseError(const char *Err, const std::string &Line) {
Printf("DataFlowTrace: parse error: %s: Line: %s\n", Err, Line.c_str());
return false;
@@ -240,24 +246,74 @@
const Vector<SizedFile> &CorporaFiles) {
Printf("INFO: collecting data flow: bin: %s dir: %s files: %zd\n",
DFTBinary.c_str(), DirPath.c_str(), CorporaFiles.size());
- setenv("DFSAN_OPTIONS", "fast16labels=1:warn_unimplemented=0", 1);
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.
- auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File)));
std::unordered_map<size_t, Vector<uint8_t>> DFTMap;
std::unordered_set<std::string> Cov;
- Command Cmd;
- Cmd.addArgument(DFTBinary);
- Cmd.addArgument(F.File);
- Cmd.addArgument(OutPath);
- Printf("CMD: %s\n", Cmd.toString().c_str());
- ExecuteCommand(Cmd);
+ 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 if it's currently empty or doesn't exist.
auto FunctionsTxtPath = DirPlusFile(DirPath, kFunctionsTxt);
if (FileToString(FunctionsTxtPath).empty()) {