[llvm] r284554 - [libFuzzer] extend -print_coverage to also print uncovered lines, functions, and files.

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 18 17:12:04 PDT 2016


Author: kcc
Date: Tue Oct 18 19:12:03 2016
New Revision: 284554

URL: http://llvm.org/viewvc/llvm-project?rev=284554&view=rev
Log:
[libFuzzer] extend -print_coverage to also print uncovered lines, functions, and files.

Example of output:
COVERAGE:
COVERED: in DSO2(int) /pathto/DSO2.cpp:6
COVERED: in DSO2(int) /pathto/DSO2.cpp:8
COVERED: in DSO1(int) /pathto/DSO1.cpp:6
COVERED: in DSO1(int) /pathto/DSO1.cpp:8
COVERED: in LLVMFuzzerTestOneInput /pathto/DSOTestMain.cpp:16
COVERED: in LLVMFuzzerTestOneInput /pathto/DSOTestMain.cpp:19
COVERED: in LLVMFuzzerTestOneInput /pathto/DSOTestMain.cpp:25
COVERED: in LLVMFuzzerTestOneInput /pathto/DSOTestMain.cpp:26
MODULE_WITH_COVERAGE: /pathto/libLLVMFuzzer-DSO1.so
UNCOVERED_LINE: in DSO1(int) /pathto/DSO1.cpp:9
UNCOVERED_FUNC: in Uncovered1()
MODULE_WITH_COVERAGE: /pathto/libLLVMFuzzer-DSO2.so
UNCOVERED_LINE: in DSO2(int) /pathto/DSO2.cpp:9
UNCOVERED_FUNC: in Uncovered2()
MODULE_WITH_COVERAGE: /pathto/LLVMFuzzer-DSOTest
UNCOVERED_LINE: in LLVMFuzzerTestOneInput /pathto/DSOTestMain.cpp:21
UNCOVERED_LINE: in LLVMFuzzerTestOneInput /pathto/DSOTestMain.cpp:27
UNCOVERED_FILE: /pathto/DSOTestExtra.cpp

Several things are not perfect here:
* we are using objdump+awk instead of sancov because sancov does not support DSOs yet.
* this breaks in the presence of ASAN_OPTIONS=strip_path_prefix=...
  (need to implement another API to get the module name by PC)



Modified:
    llvm/trunk/lib/Fuzzer/FuzzerDefs.h
    llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
    llvm/trunk/lib/Fuzzer/FuzzerUtil.cpp
    llvm/trunk/lib/Fuzzer/test/DSO1.cpp
    llvm/trunk/lib/Fuzzer/test/DSO2.cpp
    llvm/trunk/lib/Fuzzer/test/DSOTestMain.cpp
    llvm/trunk/lib/Fuzzer/test/coverage.test

Modified: llvm/trunk/lib/Fuzzer/FuzzerDefs.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDefs.h?rev=284554&r1=284553&r2=284554&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDefs.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDefs.h Tue Oct 18 19:12:03 2016
@@ -93,6 +93,8 @@ void SetSigIntHandler();
 void SetSigTermHandler();
 std::string Base64(const Unit &U);
 int ExecuteCommand(const std::string &Command);
+bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out);
+
 size_t GetPeakRSSMb();
 
 // Private copy of SHA1 implementation.

Modified: llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp?rev=284554&r1=284553&r2=284554&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp Tue Oct 18 19:12:03 2016
@@ -12,9 +12,14 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <map>
+#include <set>
+#include <sstream>
+
 #include "FuzzerCorpus.h"
 #include "FuzzerDefs.h"
 #include "FuzzerDictionary.h"
+#include "FuzzerExtFunctions.h"
 #include "FuzzerTracePC.h"
 #include "FuzzerValueBitMap.h"
 
@@ -112,11 +117,100 @@ void TracePC::HandleCallerCallee(uintptr
   HandleValueProfile(Idx);
 }
 
+static bool IsInterestingCoverageFile(std::string &File) {
+  if (File.find("compiler-rt/lib/") != std::string::npos)
+    return false; // sanitizer internal.
+  if (File.find("/usr/lib/") != std::string::npos)
+    return false;
+  if (File.find("/usr/include/") != std::string::npos)
+    return false;
+  if (File == "<null>")
+    return false;
+  return true;
+}
+
 void TracePC::PrintCoverage() {
+  if (!EF->__sanitizer_symbolize_pc) {
+    Printf("INFO: __sanitizer_symbolize_pc is not available,"
+           " not printing coverage\n");
+    return;
+  }
+  std::map<std::string, std::vector<uintptr_t>> CoveredPCsPerModule;
+  std::map<std::string, uintptr_t> ModuleOffsets;
+  std::set<std::string> CoveredFiles, CoveredFunctions, CoveredLines;
   Printf("COVERAGE:\n");
   for (size_t i = 0; i < Min(NumGuards + 1, kNumPCs); i++) {
-    if (PCs[i])
-      PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]);
+    if (!PCs[i]) continue;
+    std::string FileStr = DescribePC("%s", PCs[i]);
+    if (!IsInterestingCoverageFile(FileStr)) continue;
+    std::string FixedPCStr = DescribePC("%p", PCs[i]);
+    std::string FunctionStr = DescribePC("%F", PCs[i]);
+    std::string LineStr = DescribePC("%l", PCs[i]);
+    // TODO(kcc): get the module using some other way since this
+    // does not work with ASAN_OPTIONS=strip_path_prefix=something.
+    std::string Module = DescribePC("%m", PCs[i]);
+    std::string OffsetStr = DescribePC("%o", PCs[i]);
+    uintptr_t FixedPC = std::stol(FixedPCStr, 0, 16);
+    uintptr_t PcOffset = std::stol(OffsetStr, 0, 16);
+    ModuleOffsets[Module] = FixedPC - PcOffset;
+    CoveredPCsPerModule[Module].push_back(PcOffset);
+    CoveredFunctions.insert(FunctionStr);
+    CoveredFiles.insert(FileStr);
+    if (!CoveredLines.insert(FileStr + ":" + LineStr).second)
+      continue;
+    Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(),
+           FileStr.c_str(), LineStr.c_str());
+  }
+
+  for (auto &M : CoveredPCsPerModule) {
+    std::set<std::string> UncoveredFiles, UncoveredFunctions;
+    std::map<std::string, std::set<int> > UncoveredLines;  // Func+File => lines
+    auto &ModuleName = M.first;
+    auto &CoveredOffsets = M.second;
+    uintptr_t ModuleOffset = ModuleOffsets[ModuleName];
+    std::sort(CoveredOffsets.begin(), CoveredOffsets.end());
+    Printf("MODULE_WITH_COVERAGE: %s\n", ModuleName.c_str());
+    // sancov does not yet fully support DSOs.
+    // std::string Cmd = "sancov -print-coverage-pcs " + ModuleName;
+    std::string Cmd = "objdump -d " + ModuleName +
+        " | grep 'call.*__sanitizer_cov_trace_pc_guard' | awk -F: '{print $1}'";
+    std::string SanCovOutput;
+    if (!ExecuteCommandAndReadOutput(Cmd, &SanCovOutput)) {
+      Printf("INFO: Command failed: %s\n", Cmd.c_str());
+      continue;
+    }
+    std::istringstream ISS(SanCovOutput);
+    std::string S;
+    while (std::getline(ISS, S, '\n')) {
+      uintptr_t PcOffset = std::stol(S, 0, 16);
+      if (!std::binary_search(CoveredOffsets.begin(), CoveredOffsets.end(),
+                              PcOffset)) {
+        uintptr_t PC = ModuleOffset + PcOffset;
+        auto FileStr = DescribePC("%s", PC);
+        if (!IsInterestingCoverageFile(FileStr)) continue;
+        if (CoveredFiles.count(FileStr) == 0) {
+          UncoveredFiles.insert(FileStr);
+          continue;
+        }
+        auto FunctionStr = DescribePC("%F", PC);
+        if (CoveredFunctions.count(FunctionStr) == 0) {
+          UncoveredFunctions.insert(FunctionStr);
+          continue;
+        }
+        std::string LineStr = DescribePC("%l", PC);
+        uintptr_t Line = std::stoi(LineStr);
+        std::string FileLineStr = FileStr + ":" + LineStr;
+        if (CoveredLines.count(FileLineStr) == 0)
+          UncoveredLines[FunctionStr + " " + FileStr].insert(Line);
+      }
+    }
+    for (auto &FileLine: UncoveredLines)
+      for (int Line : FileLine.second)
+        Printf("UNCOVERED_LINE: %s:%d\n", FileLine.first.c_str(), Line);
+    for (auto &Func : UncoveredFunctions)
+      Printf("UNCOVERED_FUNC: %s\n", Func.c_str());
+    for (auto &File : UncoveredFiles)
+      Printf("UNCOVERED_FILE: %s\n", File.c_str());
   }
 }
 

Modified: llvm/trunk/lib/Fuzzer/FuzzerUtil.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerUtil.cpp?rev=284554&r1=284553&r2=284554&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerUtil.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerUtil.cpp Tue Oct 18 19:12:03 2016
@@ -19,6 +19,7 @@
 #include <cassert>
 #include <chrono>
 #include <cstring>
+#include <stdio.h>
 #include <signal.h>
 #include <sstream>
 #include <unistd.h>
@@ -306,4 +307,14 @@ void PrintPC(const char *SymbolizedFMT,
     Printf(FallbackFMT, PC);
 }
 
+bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) {
+  FILE *Pipe = popen(Command.c_str(), "r");
+  if (!Pipe) return false;
+  char Buff[1024];
+  size_t N;
+  while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0)
+    Out->append(Buff, N);
+  return true;
+}
+
 }  // namespace fuzzer

Modified: llvm/trunk/lib/Fuzzer/test/DSO1.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/DSO1.cpp?rev=284554&r1=284553&r2=284554&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/DSO1.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/DSO1.cpp Tue Oct 18 19:12:03 2016
@@ -9,3 +9,4 @@ int DSO1(int a) {
   return 1;
 }
 
+void Uncovered1() { }

Modified: llvm/trunk/lib/Fuzzer/test/DSO2.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/DSO2.cpp?rev=284554&r1=284553&r2=284554&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/DSO2.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/DSO2.cpp Tue Oct 18 19:12:03 2016
@@ -9,3 +9,4 @@ int DSO2(int a) {
   return 1;
 }
 
+void Uncovered2() {}

Modified: llvm/trunk/lib/Fuzzer/test/DSOTestMain.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/DSOTestMain.cpp?rev=284554&r1=284553&r2=284554&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/DSOTestMain.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/DSOTestMain.cpp Tue Oct 18 19:12:03 2016
@@ -11,17 +11,21 @@ extern int DSO1(int a);
 extern int DSO2(int a);
 extern int DSOTestExtra(int a);
 
+static volatile int *nil = 0;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-  if (Size < sizeof(int) * 3) return 0;
   int x, y, z;
-  memcpy(&x, Data + 0 * sizeof(int), sizeof(int));
-  memcpy(&y, Data + 1 * sizeof(int), sizeof(int));
-  memcpy(&z, Data + 2 * sizeof(int), sizeof(int));
-  int sum = DSO1(x) + DSO2(y) + DSOTestExtra(z);
+  if (Size < sizeof(int) * 3) {
+    x = y = z = 0;
+  } else {
+    memcpy(&x, Data + 0 * sizeof(int), sizeof(int));
+    memcpy(&y, Data + 1 * sizeof(int), sizeof(int));
+    memcpy(&z, Data + 2 * sizeof(int), sizeof(int));
+  }
+  int sum = DSO1(x) + DSO2(y) + (z ? DSOTestExtra(z) : 0);
   if (sum == 3) {
     fprintf(stderr, "BINGO %d %d %d\n", x, y, z);
-    exit(1);
+    *nil = 0;
   }
   return 0;
 }

Modified: llvm/trunk/lib/Fuzzer/test/coverage.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/coverage.test?rev=284554&r1=284553&r2=284554&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/coverage.test (original)
+++ llvm/trunk/lib/Fuzzer/test/coverage.test Tue Oct 18 19:12:03 2016
@@ -4,3 +4,15 @@ CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerT
 CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:16
 CHECK-DAG: COVERED: {{.*}}in LLVMFuzzerTestOneInput {{.*}}NullDerefTest.cpp:19
 RUN: not LLVMFuzzer-NullDerefTest-TracePC -print_coverage=1 2>&1 | FileCheck %s
+
+RUN: LLVMFuzzer-DSOTest -print_coverage=1 -runs=0 2>&1 | FileCheck %s --check-prefix=DSO
+DSO: COVERAGE:
+DSO-DAG: COVERED:{{.*}}DSO1{{.*}}DSO1.cpp
+DSO-DAG: COVERED:{{.*}}DSO2{{.*}}DSO2.cpp
+DSO-DAG: COVERED:{{.*}}LLVMFuzzerTestOneInput{{.*}}DSOTestMain
+DSO-DAG: UNCOVERED_LINE:{{.*}}DSO1{{.*}}DSO1.cpp
+DSO-DAG: UNCOVERED_LINE:{{.*}}DSO2{{.*}}DSO2.cpp
+DSO-DAG: UNCOVERED_FUNC: in Uncovered1
+DSO-DAG: UNCOVERED_FUNC: in Uncovered2
+DSO-DAG: UNCOVERED_LINE: in LLVMFuzzerTestOneInput
+DSO-DAG: UNCOVERED_FILE:{{.*}}DSOTestExtra.cpp




More information about the llvm-commits mailing list