[llvm] r268937 - Separate the Verifier into an analysis and a transformation pass and

Adrian Prantl via llvm-commits llvm-commits at lists.llvm.org
Mon May 9 10:37:42 PDT 2016


Author: adrian
Date: Mon May  9 12:37:42 2016
New Revision: 268937

URL: http://llvm.org/viewvc/llvm-project?rev=268937&view=rev
Log:
Separate the Verifier into an analysis and a transformation pass and
allow the transformation to strip invalid debug info.

This patch separates the Verifier into an analysis and a transformation
pass, with the transformation pass optionally stripping malformed
debug info.

The problem I'm trying to solve with this sequence of patches is that
historically we've done a really bad job at verifying debug info. We want
to be able to make the verifier stricter without having to worry about
breaking bitcode compatibility with existing producers. For example, we
don't necessarily want IR produced by an older version of clang to be
rejected by an LTO link just because of malformed debug info, and rather
provide an option to strip it. Note that merely outdated (but well-formed)
debug info would continue to be auto-upgraded in this scenario.

http://reviews.llvm.org/D19988
rdar://problem/25818489

Modified:
    llvm/trunk/include/llvm/IR/DiagnosticInfo.h
    llvm/trunk/include/llvm/IR/Verifier.h
    llvm/trunk/lib/IR/DiagnosticInfo.cpp
    llvm/trunk/lib/IR/Verifier.cpp
    llvm/trunk/lib/Passes/PassRegistry.def
    llvm/trunk/unittests/IR/VerifierTest.cpp

Modified: llvm/trunk/include/llvm/IR/DiagnosticInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/DiagnosticInfo.h?rev=268937&r1=268936&r2=268937&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/DiagnosticInfo.h (original)
+++ llvm/trunk/include/llvm/IR/DiagnosticInfo.h Mon May  9 12:37:42 2016
@@ -51,6 +51,7 @@ enum DiagnosticKind {
   DK_StackSize,
   DK_Linker,
   DK_DebugMetadataVersion,
+  DK_DebugMetadataInvalid,
   DK_SampleProfile,
   DK_OptimizationRemark,
   DK_OptimizationRemarkMissed,
@@ -214,6 +215,29 @@ public:
   }
 };
 
+/// Diagnostic information for stripping invalid debug metadata.
+class DiagnosticInfoIgnoringInvalidDebugMetadata : public DiagnosticInfo {
+private:
+  /// The module that is concerned by this debug metadata version diagnostic.
+  const Module &M;
+
+public:
+  /// \p The module that is concerned by this debug metadata version diagnostic.
+  DiagnosticInfoIgnoringInvalidDebugMetadata(
+      const Module &M, DiagnosticSeverity Severity = DS_Warning)
+      : DiagnosticInfo(DK_DebugMetadataVersion, Severity), M(M) {}
+
+  const Module &getModule() const { return M; }
+
+  /// \see DiagnosticInfo::print.
+  void print(DiagnosticPrinter &DP) const override;
+
+  static bool classof(const DiagnosticInfo *DI) {
+    return DI->getKind() == DK_DebugMetadataInvalid;
+  }
+};
+
+
 /// Diagnostic information for the sample profiler.
 class DiagnosticInfoSampleProfile : public DiagnosticInfo {
 public:

Modified: llvm/trunk/include/llvm/IR/Verifier.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Verifier.h?rev=268937&r1=268936&r2=268937&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Verifier.h (original)
+++ llvm/trunk/include/llvm/IR/Verifier.h Mon May  9 12:37:42 2016
@@ -52,6 +52,28 @@ bool verifyFunction(const Function &F, r
 bool verifyModule(const Module &M, raw_ostream *OS = nullptr,
                   bool *BrokenDebugInfo = nullptr);
 
+FunctionPass *createVerifierPass(bool FatalErrors = true);
+
+/// Check a module for errors, and report separate error states for IR
+/// and debug info errors.
+class VerifierAnalysis : public AnalysisInfoMixin<VerifierAnalysis> {
+  friend AnalysisInfoMixin<VerifierAnalysis>;
+  static char PassID;
+
+public:
+  struct Result {
+    bool IRBroken, DebugInfoBroken;
+  };
+  static void *ID() { return (void *)&PassID; }
+  Result run(Module &M);
+  Result run(Function &F);
+};
+
+/// Check a module for errors, but report debug info errors separately.
+/// Otherwise behaves as the normal verifyModule. Debug info errors can be
+/// "recovered" from by stripping the debug info.
+bool verifyModule(bool &BrokenDebugInfo, const Module &M, raw_ostream *OS);
+
 /// \brief Create a verifier pass.
 ///
 /// Check a module or function for validity. This is essentially a pass wrapped
@@ -62,18 +84,17 @@ bool verifyModule(const Module &M, raw_o
 ///
 /// Note that this creates a pass suitable for the legacy pass manager. It has
 /// nothing to do with \c VerifierPass.
-FunctionPass *createVerifierPass(bool FatalErrors = true);
-
 class VerifierPass : public PassInfoMixin<VerifierPass> {
   bool FatalErrors;
 
 public:
   explicit VerifierPass(bool FatalErrors = true) : FatalErrors(FatalErrors) {}
 
-  PreservedAnalyses run(Module &M);
-  PreservedAnalyses run(Function &F);
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
 
+
 } // End llvm namespace
 
 #endif

Modified: llvm/trunk/lib/IR/DiagnosticInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/DiagnosticInfo.cpp?rev=268937&r1=268936&r2=268937&view=diff
==============================================================================
--- llvm/trunk/lib/IR/DiagnosticInfo.cpp (original)
+++ llvm/trunk/lib/IR/DiagnosticInfo.cpp Mon May  9 12:37:42 2016
@@ -122,6 +122,11 @@ void DiagnosticInfoDebugMetadataVersion:
      << ") in " << getModule();
 }
 
+void DiagnosticInfoIgnoringInvalidDebugMetadata::print(
+    DiagnosticPrinter &DP) const {
+  DP << "ignoring invalid debug info in " << getModule().getModuleIdentifier();
+}
+
 void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const {
   if (!FileName.empty()) {
     DP << getFileName();

Modified: llvm/trunk/lib/IR/Verifier.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=268937&r1=268936&r2=268937&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Verifier.cpp (original)
+++ llvm/trunk/lib/IR/Verifier.cpp Mon May  9 12:37:42 2016
@@ -59,6 +59,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/InstIterator.h"
@@ -4482,15 +4483,38 @@ FunctionPass *llvm::createVerifierPass(b
   return new VerifierLegacyPass(FatalErrors);
 }
 
-PreservedAnalyses VerifierPass::run(Module &M) {
-  if (verifyModule(M, &dbgs()) && FatalErrors)
-    report_fatal_error("Broken module found, compilation aborted!");
+char VerifierAnalysis::PassID;
+VerifierAnalysis::Result VerifierAnalysis::run(Module &M) {
+  Result Res;
+  Res.IRBroken = llvm::verifyModule(M, &dbgs(), &Res.DebugInfoBroken);
+  return Res;
+}
+
+VerifierAnalysis::Result VerifierAnalysis::run(Function &F) {
+  return { llvm::verifyFunction(F, &dbgs()), false };
+}
 
+PreservedAnalyses VerifierPass::run(Module &M, ModuleAnalysisManager &AM) {
+  auto Res = AM.getResult<VerifierAnalysis>(M);
+  if (FatalErrors) {
+    if (Res.IRBroken)
+      report_fatal_error("Broken module found, compilation aborted!");
+    assert(!Res.DebugInfoBroken && "Module contains invalid debug info");
+  }
+
+  // Strip broken debug info.
+  if (Res.DebugInfoBroken) {
+    DiagnosticInfoIgnoringInvalidDebugMetadata DiagInvalid(M);
+    M.getContext().diagnose(DiagInvalid);
+    if (!StripDebugInfo(M))
+      report_fatal_error("Failed to strip malformed debug info");
+  }
   return PreservedAnalyses::all();
 }
 
-PreservedAnalyses VerifierPass::run(Function &F) {
-  if (verifyFunction(F, &dbgs()) && FatalErrors)
+PreservedAnalyses VerifierPass::run(Function &F, FunctionAnalysisManager &AM) {
+  auto res = AM.getResult<VerifierAnalysis>(F);
+  if (res.IRBroken && FatalErrors)
     report_fatal_error("Broken function found, compilation aborted!");
 
   return PreservedAnalyses::all();

Modified: llvm/trunk/lib/Passes/PassRegistry.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/PassRegistry.def?rev=268937&r1=268936&r2=268937&view=diff
==============================================================================
--- llvm/trunk/lib/Passes/PassRegistry.def (original)
+++ llvm/trunk/lib/Passes/PassRegistry.def Mon May  9 12:37:42 2016
@@ -23,6 +23,7 @@ MODULE_ANALYSIS("callgraph", CallGraphAn
 MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
 MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis())
 MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
+MODULE_ANALYSIS("verify", VerifierAnalysis())
 
 #ifndef MODULE_ALIAS_ANALYSIS
 #define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS)                             \
@@ -87,6 +88,7 @@ FUNCTION_ANALYSIS("scalar-evolution", Sc
 FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
 FUNCTION_ANALYSIS("targetir",
                   TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())
+FUNCTION_ANALYSIS("verify", VerifierAnalysis())
 
 #ifndef FUNCTION_ALIAS_ANALYSIS
 #define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS)                             \

Modified: llvm/trunk/unittests/IR/VerifierTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/VerifierTest.cpp?rev=268937&r1=268936&r2=268937&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/VerifierTest.cpp (original)
+++ llvm/trunk/unittests/IR/VerifierTest.cpp Mon May  9 12:37:42 2016
@@ -144,5 +144,30 @@ TEST(VerifierTest, CrossModuleMetadataRe
   EXPECT_TRUE(StringRef(ErrorOS.str())
                   .startswith("Referencing global in another module!"));
 }
+
+TEST(VerifierTest, StripInvalidDebugInfo) {
+  LLVMContext C;
+  Module M("M", C);
+  DIBuilder DIB(M);
+  DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/",
+                        "unittest", false, "", 0);
+  DIB.finalize();
+  EXPECT_FALSE(verifyModule(M));
+
+  // Now break it.
+  auto *File = DIB.createFile("not-a-CU.f", ".");
+  NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
+  NMD->addOperand(File);
+  EXPECT_TRUE(verifyModule(M));
+
+  ModulePassManager MPM(true);
+  MPM.addPass(VerifierPass(false));
+  ModuleAnalysisManager MAM(true);
+  MAM.registerPass([&] { return VerifierAnalysis(); });
+  MPM.run(M, MAM);
+  EXPECT_FALSE(verifyModule(M));
+}
+
+
 } // end anonymous namespace
 } // end namespace llvm




More information about the llvm-commits mailing list