summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeonard Chan <leonardchan@google.com>2019-07-11 22:35:40 +0000
committerLeonard Chan <leonardchan@google.com>2019-07-11 22:35:40 +0000
commit662598e8c92f140595bb1a54bab8ca0685910ad2 (patch)
tree8a395418426500c514e8702ffb5d86ac4540c5f9
parent4d4145f7422520a34ebb6324ca883bd58c81c58a (diff)
downloadclang-662598e8c92f140595bb1a54bab8ca0685910ad2.tar.gz
[NewPM] Port Sancov
This patch contains a port of SanitizerCoverage to the new pass manager. This one's a bit hefty. Changes: - Split SanitizerCoverageModule into 2 SanitizerCoverage for passing over functions and ModuleSanitizerCoverage for passing over modules. - ModuleSanitizerCoverage exists for adding 2 module level calls to initialization functions but only if there's a function that was instrumented by sancov. - Added legacy and new PM wrapper classes that own instances of the 2 new classes. - Update llvm tests and add clang tests. Differential Revision: https://reviews.llvm.org/D62888 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@365838 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/BackendUtil.cpp47
-rw-r--r--test/CodeGen/sancov-new-pm.c41
2 files changed, 81 insertions, 7 deletions
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 40a529c319..8499af07db 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -60,6 +60,7 @@
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
+#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
@@ -195,11 +196,8 @@ static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
PM.add(createBoundsCheckingLegacyPass());
}
-static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+static SanitizerCoverageOptions
+getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
SanitizerCoverageOptions Opts;
Opts.CoverageType =
static_cast<SanitizerCoverageOptions::Type>(CGOpts.SanitizeCoverageType);
@@ -215,7 +213,17 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters;
Opts.PCTable = CGOpts.SanitizeCoveragePCTable;
Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth;
- PM.add(createSanitizerCoverageModulePass(Opts));
+ return Opts;
+}
+
+static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
+ legacy::PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper &>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ auto Opts = getSancovOptsFromCGOpts(CGOpts);
+ PM.add(createModuleSanitizerCoverageLegacyPassPass(Opts));
+ PM.add(createSanitizerCoverageLegacyPassPass(Opts));
}
// Check if ASan should use GC-friendly instrumentation for globals.
@@ -1135,6 +1143,21 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
EntryExitInstrumenterPass(/*PostInlining=*/false)));
});
+ if (CodeGenOpts.SanitizeCoverageType ||
+ CodeGenOpts.SanitizeCoverageIndirectCalls ||
+ CodeGenOpts.SanitizeCoverageTraceCmp) {
+ auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
+ PB.registerPipelineStartEPCallback(
+ [SancovOpts](ModulePassManager &MPM) {
+ MPM.addPass(ModuleSanitizerCoveragePass(SancovOpts));
+ });
+ PB.registerOptimizerLastEPCallback(
+ [SancovOpts](FunctionPassManager &FPM,
+ PassBuilder::OptimizationLevel Level) {
+ FPM.addPass(SanitizerCoveragePass(SancovOpts));
+ });
+ }
+
// Register callbacks to schedule sanitizer passes at the appropriate part of
// the pipeline.
// FIXME: either handle asan/the remaining sanitizers or error out
@@ -1219,8 +1242,18 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
}
}
- if (CodeGenOpts.OptimizationLevel == 0)
+ if (CodeGenOpts.OptimizationLevel == 0) {
+ if (CodeGenOpts.SanitizeCoverageType ||
+ CodeGenOpts.SanitizeCoverageIndirectCalls ||
+ CodeGenOpts.SanitizeCoverageTraceCmp) {
+ auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
+ MPM.addPass(ModuleSanitizerCoveragePass(SancovOpts));
+ MPM.addPass(createModuleToFunctionPassAdaptor(
+ SanitizerCoveragePass(SancovOpts)));
+ }
+
addSanitizersAtO0(MPM, TargetTriple, LangOpts, CodeGenOpts);
+ }
}
// FIXME: We still use the legacy pass manager to do code generation. We
diff --git a/test/CodeGen/sancov-new-pm.c b/test/CodeGen/sancov-new-pm.c
new file mode 100644
index 0000000000..06d9042bc7
--- /dev/null
+++ b/test/CodeGen/sancov-new-pm.c
@@ -0,0 +1,41 @@
+// Test that SanitizerCoverage works under the new pass manager.
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -O2 -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O2
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto -O2 -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O2
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto=thin -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O0
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=fuzzer %s -fexperimental-new-pass-manager -flto=thin -O2 -S -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,CHECK-O2,CHECK-O2-THINLTO
+
+extern void *memcpy(void *, const void *, unsigned long);
+extern int printf(const char *restrict, ...);
+
+int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) {
+ unsigned char buf[4];
+
+ if (size < 8)
+ return 0;
+
+ if (data[0] == 'h' && data[1] == 'i' && data[2] == '!') {
+ memcpy(buf, data, size);
+ printf("test: %.2X\n", buf[0]);
+ }
+
+ return 0;
+}
+
+// CHECK-DAG: declare void @__sanitizer_cov_pcs_init(i64*, i64*)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_pc_indir(i64)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_cmp1(i8 zeroext, i8 zeroext)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_cmp2(i16 zeroext, i16 zeroext)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_cmp4(i32 zeroext, i32 zeroext)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_cmp8(i64, i64)
+// CHECK-O2-THINLTO-NOT: declare void @__sanitizer_cov_trace_const_cmp1(i8 zeroext, i8 zeroext)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_const_cmp2(i16 zeroext, i16 zeroext)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_const_cmp4(i32 zeroext, i32 zeroext)
+// CHECK-O2-THINLTO-NOT: declare void @__sanitizer_cov_trace_const_cmp8(i64, i64)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_div4(i32 zeroext)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_div8(i64)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_gep(i64)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_switch(i64, i64*)
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_pc()
+// CHECK-O0-DAG: declare void @__sanitizer_cov_trace_pc_guard(i32*)