Unverified Commit 81518d06 authored by Jiang Ning's avatar Jiang Ning Committed by GitHub
Browse files

[DebugInfo] Verify DISubprogram has a type (#194556)

Require DISubprogram metadata to carry a non-null type in the verifier.

LangRef specifies that the `type:` field of `DISubprogram` points to a
`DISubroutineType`. This patch diagnoses malformed debug info where the
field is omitted or resolves to null, while preserving the existing wrong-type
diagnostic for non-DISubroutineType operands.

Update hand-written LLVM IR tests to use valid DISubprogram metadata
where they are not intentionally testing malformed debug info. These tests now 
use minimal DISubroutineType metadata so the new verifier check does not mask 
their original coverage.

Fixes #186557
parent 15383dcd
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -30,7 +30,9 @@ entry:

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1)
!1 = !DIFile(filename: "test.c", directory: "")
!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, unit: !0)
!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !14, unit: !0)
!9 = !{i32 2, !"Dwarf Version", i32 4}
!10 = !{i32 2, !"Debug Info Version", i32 3}
!13 = !DILocation(line: 2, column: 20, scope: !4)
!14 = !DISubroutineType(types: !15)
!15 = !{null}
+3 −2
Original line number Diff line number Diff line
@@ -1657,7 +1657,8 @@ void Verifier::visitDISubprogram(const DISubprogram &N) {
    CheckDI(isa<DIFile>(F), "invalid file", &N, F);
  else
    CheckDI(N.getLine() == 0, "line specified with no file", &N, N.getLine());
  if (auto *T = N.getRawType())
  auto *T = N.getRawType();
  CheckDI(T, "DISubprogram requires a non-null type", &N);
  CheckDI(isa<DISubroutineType>(T), "invalid subroutine type", &N, T);
  CheckDI(isType(N.getRawContainingType()), "invalid containing type", &N,
          N.getRawContainingType());
+3 −1
Original line number Diff line number Diff line
@@ -26,9 +26,11 @@ exit:
!llvm.module.flags = !{!5, !6, !7}

!0 = !DIFile(filename: "negative_step.c", directory: "/")
!1 = distinct !DISubprogram(name: "negative_step", scope: !0, file: !0, unit: !4)
!1 = distinct !DISubprogram(name: "negative_step", scope: !0, file: !0, type: !8, unit: !4)
!2 = !DILocation(line: 5, column: 2, scope: !1)
!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !0, producer: "clang")
!5 = !{i32 1, !"Debug Info Version", i32 3}
!6 = !{i32 2, !"Dwarf Version", i32 2}
!7 = !{i32 1, !"PIC Level", i32 2}
!8 = !DISubroutineType(types: !9)
!9 = !{null}
+20 −16
Original line number Diff line number Diff line
@@ -16,39 +16,43 @@
; CHECK-NEXT: !3 = !DICompositeType(tag: DW_TAG_structure_type, name: "has-uuid",{{.*}}, identifier: "uuid")
; CHECK-NEXT: !4 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !3, file: !1
; CHECK-NEXT: !5 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !3, file: !1
; CHECK-NEXT: !6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !3, file: !1
; CHECK-NEXT: !7 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !3, file: !1
; CHECK-NEXT: !6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !3, file: !1, type: !7, spFlags: 0)
; CHECK-NEXT: !7 = !DISubroutineType(types: !8)
; CHECK-NEXT: !8 = !{null}
; CHECK-NEXT: !9 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !3, file: !1, type: !7, spFlags: 0)
!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "has-uuid", file: !1, line: 2, size: 64, align: 32, identifier: "uuid")
!4 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !3, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
!5 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !3, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
!6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !3, file: !1, isDefinition: false)
!7 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !3, file: !1, isDefinition: false)
!6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !3, file: !1, isDefinition: false, type: !18)
!7 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !3, file: !1, isDefinition: false, type: !18)
!18 = !DISubroutineType(types: !19)
!19 = !{null}

; Define an un-identified type with fields and functions.
; CHECK-NEXT: !8 = !DICompositeType(tag: DW_TAG_structure_type, name: "no-uuid", file: !1
; CHECK-NEXT: !9 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !1
; CHECK-NEXT: !10 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !8, file: !1
; CHECK-NEXT: !11 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !1
; CHECK-NEXT: !12 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !8, file: !1
; CHECK-NEXT: !10 = !DICompositeType(tag: DW_TAG_structure_type, name: "no-uuid", file: !1
; CHECK-NEXT: !11 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !10, file: !1
; CHECK-NEXT: !12 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !10, file: !1
; CHECK-NEXT: !13 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !10, file: !1, type: !7, spFlags: 0)
; CHECK-NEXT: !14 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !10, file: !1, type: !7, spFlags: 0)
!8 = !DICompositeType(tag: DW_TAG_structure_type, name: "no-uuid", file: !1, line: 2, size: 64, align: 32)
!9 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
!10 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !8, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
!11 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !1, isDefinition: false)
!12 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !8, file: !1, isDefinition: false)
!11 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !1, isDefinition: false, type: !18)
!12 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !8, file: !1, isDefinition: false, type: !18)

; Add duplicate fields and members of "no-uuid" in a different file.  These
; should stick around, since "no-uuid" does not have an "identifier:" field.
; CHECK-NEXT: !13 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !2,
; CHECK-NEXT: !14 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !2,
; CHECK-NEXT: !15 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !10, file: !2,
; CHECK-NEXT: !16 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !10, file: !2, type: !7, spFlags: 0)
!13 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !2, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
!14 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !2, isDefinition: false)
!14 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !2, isDefinition: false, type: !18)

; Add duplicate fields and members of "has-uuid" in a different file.  These
; should be merged.
!15 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !3, file: !2, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
!16 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !3, file: !2, isDefinition: false)
!16 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !3, file: !2, isDefinition: false, type: !18)

; CHECK-NEXT: !15 = !{!4, !6}
; CHECK-NEXT: !17 = !{!4, !6}
; CHECK-NOT: !DIDerivedType
; CHECK-NOT: !DISubprogram
!17 = !{!15, !16}
+12 −6
Original line number Diff line number Diff line
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
; RUN: verify-uselistorder %s

; CHECK: !named = !{!0, !3, !4, !5, !5}
; CHECK: !named = !{!0, !5, !6, !7, !7}
!named = !{!0, !3, !4, !5, !6}

!llvm.module.flags = !{!7}
!llvm.dbg.cu = !{!1}

; CHECK:      !0 = distinct !DISubprogram({{.*}})
!0 = distinct !DISubprogram(name: "foo", isDefinition: true, unit: !1)
; CHECK:      !0 = distinct !DISubprogram({{.*}}, type: !1{{.*}})
!0 = distinct !DISubprogram(name: "foo", isDefinition: true, unit: !1, type: !8)
!8 = !DISubroutineType(types: !9)
!9 = !{null}

!1 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang",
                             file: !2,
                             isOptimized: true, flags: "-O2",
                             splitDebugFilename: "abc.debug", emissionKind: 2)
!2 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
; CHECK: !3 = !DICompositeType({{.*}})
; CHECK: !1 = !DISubroutineType(types: !2)
; CHECK: !2 = !{null}
; CHECK: !3 = distinct !DICompileUnit
; CHECK: !4 = !DIFile
; CHECK: !5 = !DICompositeType({{.*}})
!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "Class", size: 32, align: 32)

; CHECK-NEXT: !4 = !DIImportedEntity(tag: DW_TAG_imported_module, name: "foo", scope: !0, entity: !1, file: !2, line: 7)
; CHECK-NEXT: !6 = !DIImportedEntity(tag: DW_TAG_imported_module, name: "foo", scope: !0, entity: !3, file: !4, line: 7)
!4 = !DIImportedEntity(tag: DW_TAG_imported_module, name: "foo", scope: !0,
                       entity: !1, file: !2, line: 7)

; CHECK-NEXT: !5 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !0)
; CHECK-NEXT: !7 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !0)
!5 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !0)
!6 = !DIImportedEntity(tag: DW_TAG_imported_module, name: "", scope: !0, entity: null,
                       line: 0)
Loading