Skip to content

[BPF] Rust data-carrying enums cause invalid cast to DIDerivedType #155778

@vadorovsky

Description

@vadorovsky

Rust has a concept of data-carrying enums, where variants aren't just integer values, but composite types. They look like:

pub enum DataCarryingEnum {
    First { a: u32, b: i32 },
    Second(u32, i32),
    Third(u32),
}

This type's debug info is the following DICompositeType with DW_TAG_structure_type tag:

!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "DataCarryingEnum", scope: !2, file: !5, size: 96, align: 32, flags: DIFlagPublic, elements: !6, templateParams: !16, identifier: "2bc4a1fe2282cdc6dd55af802fccb261")

With one element being also a DICompositeType, but with DW_TAG_variant_part tag:

!6 = !{!7}
!7 = !DICompositeType(tag: DW_TAG_variant_part, scope: !4, file: !5, size: 96, align: 32, elements: !8, templateParams: !16, identifier: "6c4a6a604e3dcbb53b9dbd2113a7a3e2", discriminator: !26)

Which then holds different variants as DIDerivedType elements with DW_TAG_member tag:

!8 = !{!9, !17, !22}
!9 = !DIDerivedType(tag: DW_TAG_member, name: "First", scope: !7, file: !5, baseType: !10, size: 96, align: 32, extraData: i32 0)
!10 = !DICompositeType(tag: DW_TAG_structure_type, name: "First", scope: !4, file: !5, size: 96, align: 32, flags: DIFlagPublic, elements: !11, templateParams: !16, identifier: "d02872fc81dfee23fe3b1b59ad9887b8")
!11 = !{!12, !14}
!12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !5, baseType: !13, size: 32, align: 32, offset: 32, flags: DIFlagPublic)
!13 = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned)
!14 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !10, file: !5, baseType: !15, size: 32, align: 32, offset: 64, flags: DIFlagPublic)
!15 = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
!16 = !{}
!17 = !DIDerivedType(tag: DW_TAG_member, name: "Second", scope: !7, file: !5, baseType: !18, size: 96, align: 32, extraData: i32 1)
!18 = !DICompositeType(tag: DW_TAG_structure_type, name: "Second", scope: !4, file: !5, size: 96, align: 32, flags: DIFlagPublic, elements: !19, templateParams: !16, identifier: "d12042e992b976eabc7aa6ed0657048d")
!19 = !{!20, !21}
!20 = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: !18, file: !5, baseType: !13, size: 32, align: 32, offset: 32, flags: DIFlagPublic)
!21 = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: !18, file: !5, baseType: !15, size: 32, align: 32, offset: 64, flags: DIFlagPublic)
!22 = !DIDerivedType(tag: DW_TAG_member, name: "Third", scope: !7, file: !5, baseType: !23, size: 96, align: 32, extraData: i32 2)
!23 = !DICompositeType(tag: DW_TAG_structure_type, name: "Third", scope: !4, file: !5, size: 96, align: 32, flags: DIFlagPublic, elements: !24, templateParams: !16, identifier: "77e269baca088eafc02a70358f3c026c")
!24 = !{!25}
!25 = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: !23, file: !5, baseType: !13, size: 32, align: 32, offset: 32, flags: DIFlagPublic)
!26 = !DIDerivedType(tag: DW_TAG_member, scope: !4, file: !5, baseType: !13, size: 32, align: 32, flags: DIFlagArtificial)

BPF backend is assuming that all the elements of the first DICompositeType (!4) are DIDerivedTypes and uses an unchecked cast:

const auto Elem = cast<DIDerivedType>(Element);

Which causes crashes when building a Rust BPF module with data-carrying enums, when assertions are enabled:

Assertion failed: isa<To>(Val) && "cast<Ty>() argument of incompatible type!" (/home/vadorovsky/src/llvm-project/llvm/include/llvm/Support/Casting.h: cast: 578)
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions