From: Adrian Prantl Date: Tue, 28 Feb 2017 23:48:42 +0000 (+0000) Subject: Teach the IR verifier to reject conflicting debug info for function arguments. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=56d0100cfaf14fefc674d3dcd1396d62503b1c0a;p=llvm Teach the IR verifier to reject conflicting debug info for function arguments. Conflicting debug info for function arguments causes hard-to-debug assertions in the DWARF backend, so the Verifier should reject it. For performance reasons this only checks function arguments from non-inlined debug intrinsics for now. rdar://problem/30520286 This reapplies r295749 after fixing PR32042. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296543 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 90017354631..deba84dbb96 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -297,6 +297,9 @@ class Verifier : public InstVisitor, VerifierSupport { // constant expressions, we can arrive at a particular user many times. SmallPtrSet GlobalValueVisited; + // Keeps track of duplicate function argument debug info. + SmallVector DebugFnArgs; + TBAAVerifier TBAAVerifyHelper; void checkAtomicMemAccessSize(Type *Ty, const Instruction *I); @@ -498,6 +501,7 @@ private: void verifySiblingFuncletUnwinds(); void verifyFragmentExpression(const DbgInfoIntrinsic &I); + void verifyFnArgs(const DbgInfoIntrinsic &I); /// Module-level debug info verification... void verifyCompileUnits(); @@ -1947,6 +1951,8 @@ void Verifier::verifySiblingFuncletUnwinds() { // visitFunction - Verify that a function is ok. // void Verifier::visitFunction(const Function &F) { + DebugFnArgs.clear(); + visitGlobalValue(F); // Check function arguments. @@ -4349,6 +4355,8 @@ void Verifier::visitDbgIntrinsic(StringRef Kind, DbgIntrinsicTy &DII) { " variable and !dbg attachment", &DII, BB, F, Var, Var->getScope()->getSubprogram(), Loc, Loc->getScope()->getSubprogram()); + + verifyFnArgs(DII); } static uint64_t getVariableSize(const DILocalVariable &V) { @@ -4417,6 +4425,36 @@ void Verifier::verifyFragmentExpression(const DbgInfoIntrinsic &I) { AssertDI(FragSize != VarSize, "fragment covers entire variable", &I, V, E); } +void Verifier::verifyFnArgs(const DbgInfoIntrinsic &I) { + DILocalVariable *Var; + if (auto *DV = dyn_cast(&I)) { + // For performance reasons only check non-inlined ones. + if (DV->getDebugLoc()->getInlinedAt()) + return; + Var = DV->getVariable(); + } else { + auto *DD = cast(&I); + if (DD->getDebugLoc()->getInlinedAt()) + return; + Var = DD->getVariable(); + } + AssertDI(Var, "dbg intrinsic without variable"); + + unsigned ArgNo = Var->getArg(); + if (!ArgNo) + return; + + // Verify there are no duplicate function argument debug info entries. + // These will cause hard-to-debug assertions in the DWARF backend. + if (DebugFnArgs.size() < ArgNo) + DebugFnArgs.resize(ArgNo, nullptr); + + auto *Prev = DebugFnArgs[ArgNo - 1]; + DebugFnArgs[ArgNo - 1] = Var; + AssertDI(!Prev || (Prev == Var), "conflicting debug info for argument", &I, + Prev, Var); +} + void Verifier::verifyCompileUnits() { auto *CUs = M.getNamedMetadata("llvm.dbg.cu"); SmallPtrSet Listed; diff --git a/test/Verifier/fnarg-debuginfo.ll b/test/Verifier/fnarg-debuginfo.ll new file mode 100644 index 00000000000..7cbe9ce93b9 --- /dev/null +++ b/test/Verifier/fnarg-debuginfo.ll @@ -0,0 +1,26 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s + +declare void @llvm.dbg.declare(metadata, metadata, metadata) +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +define void @foo() !dbg !2 { +entry: + %a = alloca i32 + ; CHECK: conflicting debug info for argument + call void @llvm.dbg.value(metadata i32 0, i64 0, metadata !3, metadata !DIExpression()), !dbg !6 + call void @llvm.dbg.declare(metadata i32* %a, metadata !4, metadata !DIExpression()), !dbg !6 + ret void, !dbg !6 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", emissionKind: FullDebug) +!1 = !DIFile(filename: "x.c", directory: "/") +!2 = distinct !DISubprogram(name: "foo", scope: !0, isDefinition: true, unit: !0) +!3 = !DILocalVariable(name: "a", arg: 1, scope: !2, file: !1, line: 1, type: !5) +!4 = !DILocalVariable(name: "b", arg: 1, scope: !2, file: !1, line: 1, type: !5) +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!6 = !DILocation(line: 1, scope: !2) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 1, !"Debug Info Version", i32 3}