vsk created this revision. LLVM has a nifty linter which checks for some common kinds of unusual or undefined behavior by doing some basic IR-level static analysis.
Add a CC1 option to clang which enables this analysis. Having the linter available through clang could be a useful debugging tool. It can also be a useful reporting tool: hacking your build system to add in "-Xclang -enable-llvm-linter" is usually easier than hacking it to add "$CC ... | opt -S -o /dev/null -lint". Eventually, I'd like to teach the linter about the sanitizers, so that it can statically report the kinds of bugs the sanitizers know how to flag. This would work by checking for diagnostic calls which post-dom function entry blocks (unconditionally buggy code). The research paper on the STACK static UB checker suggests that this could be useful. https://reviews.llvm.org/D30949 Files: include/clang/Driver/CC1Options.td include/clang/Frontend/CodeGenOptions.def lib/CodeGen/BackendUtil.cpp lib/Frontend/CompilerInvocation.cpp test/CodeGen/enable-llvm-linter.c Index: test/CodeGen/enable-llvm-linter.c =================================================================== --- /dev/null +++ test/CodeGen/enable-llvm-linter.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -enable-llvm-linter -O0 -emit-llvm -o /dev/null %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -enable-llvm-linter -O3 -emit-llvm -o /dev/null %s 2>&1 | FileCheck %s + +// CHECK: Unusual: Address one pointer dereference +// CHECK-NEXT: load i32, i32* +int foo() { + int *p = (int *)1; + return *p; +} Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -650,6 +650,7 @@ Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + Opts.LintModule = Args.hasArg(OPT_enable_llvm_linter); Opts.DisableGCov = Args.hasArg(OPT_test_coverage); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/Lint.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeReader.h" @@ -257,6 +258,11 @@ PM.add(createEfficiencySanitizerPass(Opts)); } +static void addLinterPass(const PassManagerBuilder &Builder, + legacy::PassManagerBase &PM) { + PM.add(createLintPass()); +} + static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple, const CodeGenOptions &CodeGenOpts) { TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple); @@ -415,6 +421,12 @@ addEfficiencySanitizerPass); } + if (CodeGenOpts.LintModule) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, addLinterPass); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addLinterPass); + } + // Set up the per-function pass manager. FPM.add(new TargetLibraryInfoWrapperPass(*TLII)); if (CodeGenOpts.VerifyModule) Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -184,6 +184,9 @@ CODEGENOPT(VerifyModule , 1, 1) ///< Control whether the module should be run ///< through the LLVM Verifier. +CODEGENOPT(LintModule , 1, 0) ///< Control whether the module should be run + ///< through the LLVM Linter. + CODEGENOPT(StackRealignment , 1, 0) ///< Control whether to force stack ///< realignment. CODEGENOPT(UseInitArray , 1, 0) ///< Control whether to use .init_array or Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -164,6 +164,8 @@ def disable_llvm_verifier : Flag<["-"], "disable-llvm-verifier">, HelpText<"Don't run the LLVM IR verifier pass">; +def enable_llvm_linter : Flag<["-"], "enable-llvm-linter">, + HelpText<"Run the LLVM IR linter pass">; def disable_llvm_passes : Flag<["-"], "disable-llvm-passes">, HelpText<"Use together with -emit-llvm to get pristine LLVM IR from the " "frontend by not running any LLVM passes at all">;
Index: test/CodeGen/enable-llvm-linter.c =================================================================== --- /dev/null +++ test/CodeGen/enable-llvm-linter.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -enable-llvm-linter -O0 -emit-llvm -o /dev/null %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -enable-llvm-linter -O3 -emit-llvm -o /dev/null %s 2>&1 | FileCheck %s + +// CHECK: Unusual: Address one pointer dereference +// CHECK-NEXT: load i32, i32* +int foo() { + int *p = (int *)1; + return *p; +} Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -650,6 +650,7 @@ Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + Opts.LintModule = Args.hasArg(OPT_enable_llvm_linter); Opts.DisableGCov = Args.hasArg(OPT_test_coverage); Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/Lint.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeReader.h" @@ -257,6 +258,11 @@ PM.add(createEfficiencySanitizerPass(Opts)); } +static void addLinterPass(const PassManagerBuilder &Builder, + legacy::PassManagerBase &PM) { + PM.add(createLintPass()); +} + static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple, const CodeGenOptions &CodeGenOpts) { TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple); @@ -415,6 +421,12 @@ addEfficiencySanitizerPass); } + if (CodeGenOpts.LintModule) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, addLinterPass); + PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addLinterPass); + } + // Set up the per-function pass manager. FPM.add(new TargetLibraryInfoWrapperPass(*TLII)); if (CodeGenOpts.VerifyModule) Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -184,6 +184,9 @@ CODEGENOPT(VerifyModule , 1, 1) ///< Control whether the module should be run ///< through the LLVM Verifier. +CODEGENOPT(LintModule , 1, 0) ///< Control whether the module should be run + ///< through the LLVM Linter. + CODEGENOPT(StackRealignment , 1, 0) ///< Control whether to force stack ///< realignment. CODEGENOPT(UseInitArray , 1, 0) ///< Control whether to use .init_array or Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -164,6 +164,8 @@ def disable_llvm_verifier : Flag<["-"], "disable-llvm-verifier">, HelpText<"Don't run the LLVM IR verifier pass">; +def enable_llvm_linter : Flag<["-"], "enable-llvm-linter">, + HelpText<"Run the LLVM IR linter pass">; def disable_llvm_passes : Flag<["-"], "disable-llvm-passes">, HelpText<"Use together with -emit-llvm to get pristine LLVM IR from the " "frontend by not running any LLVM passes at all">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits