Index: include/llvm/IR/DiagnosticInfo.h =================================================================== --- include/llvm/IR/DiagnosticInfo.h +++ include/llvm/IR/DiagnosticInfo.h @@ -51,6 +51,7 @@ DK_StackSize, DK_Linker, DK_DebugMetadataVersion, + DK_DebugMetadataInvalid, DK_SampleProfile, DK_OptimizationRemark, DK_OptimizationRemarkMissed, @@ -214,6 +215,29 @@ } }; +/// 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: Index: include/llvm/IR/Verifier.h =================================================================== --- include/llvm/IR/Verifier.h +++ include/llvm/IR/Verifier.h @@ -52,6 +52,26 @@ bool verifyModule(const Module &M, raw_ostream *OS = nullptr, bool *BrokenDebugInfo = nullptr); +FunctionPass *createVerifierPass(bool FatalErrors = true); + +class VerifierAnalysis : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + 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 +82,17 @@ /// /// 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 { 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 Index: lib/IR/DiagnosticInfo.cpp =================================================================== --- lib/IR/DiagnosticInfo.cpp +++ lib/IR/DiagnosticInfo.cpp @@ -122,6 +122,11 @@ << ") in " << getModule(); } +void DiagnosticInfoIgnoringInvalidDebugMetadata::print( + DiagnosticPrinter &DP) const { + DP << "ignoring invalid debug info in " << getModule(); +} + void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const { if (!FileName.empty()) { DP << getFileName(); Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -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 @@ 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(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(F); + if (res.IRBroken && FatalErrors) report_fatal_error("Broken function found, compilation aborted!"); return PreservedAnalyses::all(); Index: lib/Passes/PassRegistry.def =================================================================== --- lib/Passes/PassRegistry.def +++ lib/Passes/PassRegistry.def @@ -23,6 +23,7 @@ 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("targetlibinfo", TargetLibraryAnalysis()) FUNCTION_ANALYSIS("targetir", TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis()) +FUNCTION_ANALYSIS("verify", VerifierAnalysis()) #ifndef FUNCTION_ALIAS_ANALYSIS #define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) \ Index: unittests/IR/VerifierTest.cpp =================================================================== --- unittests/IR/VerifierTest.cpp +++ unittests/IR/VerifierTest.cpp @@ -144,5 +144,30 @@ 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