
The function `CGDebugInfo::EmitFunctionDecl` is supposed to create a declaration -- never a _definition_ -- of a subprogram. This is made evident by the fact that the SPFlags never have the "Declaration" bit set by that function. However, when `EmitFunctionDecl` calls `DIBuilder::createFunction`, it still tries to fill the "Declaration" argument by passing it the result of `getFunctionDeclaration(D)`. This will query an internal cache of previously created declarations and, for most code paths, we return nullptr; all is good. However, as reported in [0], there are pathological cases in which we attempt to recreate a declaration, so the cache query succeeds, resulting in a subprogram declaration whose declaration field points to another declaration. Through a series of RAUWs, the declaration field ends up pointing to the SP itself. Self-referential MDNodes can't be `unique`, which causes the verifier to fail (declarations must be `unique`). We can argue that the caller should check the cache first, but this is not a correctness issue (declarations are `unique` anyway). The bug is that `CGDebugInfo::EmitFunctionDecl` should always pass `nullptr` to the declaration argument of `DIBuilder::createFunction`, expressing the fact that declarations don't point to other declarations. AFAICT this is not something for which any reasonable meaning exists. This seems a lot like a copy-paste mistake that has survived for ~10 years, since other places in this file have the exact same call almost token-by-token. I've tested this by compiling LLVMSupport with and without the patch, O2 and O0, and comparing the dwarfdump of the lib. The dumps are identical modulo the attributes decl_file/producer/comp_dir. [0]: https://github.com/llvm/llvm-project/issues/59241 Differential Revision: https://reviews.llvm.org/D143921
18 lines
789 B
LLVM
18 lines
789 B
LLVM
; RUN: llvm-as -disable-output <%s 2>&1| FileCheck %s
|
|
|
|
declare !dbg !12 i32 @declared_only()
|
|
|
|
!llvm.module.flags = !{!2}
|
|
!llvm.dbg.cu = !{!5}
|
|
|
|
!2 = !{i32 2, !"Debug Info Version", i32 3}
|
|
!5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !6, producer: "clang", emissionKind: FullDebug)
|
|
!6 = !DIFile(filename: "a.cpp", directory: "/")
|
|
!7 = !{}
|
|
!11 = !DISubroutineType(types: !7)
|
|
|
|
!12 = !DISubprogram(name: "declared_only", scope: !6, file: !6, line: 2, type: !11, spFlags: DISPFlagOptimized, retainedNodes: !7, declaration: !13)
|
|
!13 = !DISubprogram(name: "declared_only", scope: !6, file: !6, line: 2, type: !11, spFlags: DISPFlagOptimized, retainedNodes: !7)
|
|
; CHECK: subprogram declaration must not have a declaration field
|
|
; CHECK: warning: ignoring invalid debug info
|