rust-lang / rust-lang/rust

DWARF information encodes discriminant values for tagged enums incorrectly

Open
#125,147 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-debuginfo C-bug T-compiler WG-debugging
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

The Rust compiler emits tagged enums and their members as DW_TAG_variant_part and DW_TAG_variant DIEs in DWARF correspondingly. According to the DWARF standard, the discriminant value for each of the variant members should be LEB128 encoded. In practice, the Rust compiler does not encode these values in LEB128 encoding, thereby it is not compliant with the DWARF standard.

Furthermore, there seems to be some undefined behavior with negative discriminant values. The following examples show 2 cases of tagged enums with negative discriminants.


Example 1

Discriminant type is 32 bit signed integer.

#[repr(i32)]
pub enum Foo {
    Unit = -2,
    TwoInts(u32, u32) = -1,
    ThreeShorts{x: u16, y: u16, z: u16} = 0,
}

DWARF:

0x00000078:     DW_TAG_structure_type
                  DW_AT_name [DW_FORM_strp]     ("Foo")
                  DW_AT_byte_size [DW_FORM_data1]       (0x0c)
                  DW_AT_alignment [DW_FORM_udata]       (4)

0x0000007f:       DW_TAG_variant_part
                    DW_AT_discr [DW_FORM_ref4]  (0x00000084)

0x00000084:         DW_TAG_member
                      DW_AT_type [DW_FORM_ref4] (0x00000114 "i32")
                      DW_AT_alignment [DW_FORM_udata]   (4)
                      DW_AT_data_member_location [DW_FORM_data1]        (0x00)
                      DW_AT_artificial [DW_FORM_flag_present]   (true)

0x0000008b:         DW_TAG_variant
                      DW_AT_discr_value [DW_FORM_data8] (0x00000000fffffffe)

0x00000094:           DW_TAG_member
                        DW_AT_name [DW_FORM_strp]       ("Unit")
                        DW_AT_type [DW_FORM_ref4]       (0x000000bd "t3::Foo::Unit")
                        DW_AT_alignment [DW_FORM_udata] (4)
                        DW_AT_data_member_location [DW_FORM_data1]      (0x00)

0x0000009f:           NULL

0x000000a0:         DW_TAG_variant
                      DW_AT_discr_value [DW_FORM_data8] (0x00000000ffffffff)

0x000000a2:           DW_TAG_member
                        DW_AT_name [DW_FORM_strp]       ("TwoInts")
                        DW_AT_type [DW_FORM_ref4]       (0x000000c4 "t3::Foo::TwoInts")
                        DW_AT_alignment [DW_FORM_udata] (4)
                        DW_AT_data_member_location [DW_FORM_data1]      (0x00)

0x000000ad:           NULL

0x000000ae:         DW_TAG_variant
                      DW_AT_discr_value [DW_FORM_data1] (0x00)

0x000000b0:           DW_TAG_member
                        DW_AT_name [DW_FORM_strp]       ("ThreeShorts")
                        DW_AT_type [DW_FORM_ref4]       (0x000000e2 "t3::Foo::ThreeShorts")
                        DW_AT_alignment [DW_FORM_udata] (4)
                        DW_AT_data_member_location [DW_FORM_data1]      (0x00)

0x000000bb:           NULL

0x000000bc:         NULL

Example 2

Discriminant type is 64 bit signed integer.

#[repr(i64)]
pub enum Foo {
    Unit = -2,
    TwoInts(u32, u32) = -1,
    ThreeShorts{x: u16, y: u16, z: u16} = 0,
}

DWARF:

0x00000079:     DW_TAG_structure_type
                  DW_AT_name [DW_FORM_strp]     ("Foo")
                  DW_AT_byte_size [DW_FORM_data1]       (0x10)
                  DW_AT_alignment [DW_FORM_udata]       (8)

0x00000080:       DW_TAG_variant_part
                    DW_AT_discr [DW_FORM_ref4]  (0x00000085)

0x00000085:         DW_TAG_member
                      DW_AT_type [DW_FORM_ref4] (0x0000010e "i64")
                      DW_AT_alignment [DW_FORM_udata]   (8)
                      DW_AT_data_member_location [DW_FORM_data1]        (0x00)
                      DW_AT_artificial [DW_FORM_flag_present]   (true)

0x0000008c:         DW_TAG_variant
                      DW_AT_discr_value [DW_FORM_data1] (0xfe)

0x0000008e:           DW_TAG_member
                        DW_AT_name [DW_FORM_strp]       ("Unit")
                        DW_AT_type [DW_FORM_ref4]       (0x000000b7 "t3::Foo::Unit")
                        DW_AT_alignment [DW_FORM_udata] (8)
                        DW_AT_data_member_location [DW_FORM_data1]      (0x00)

0x00000099:           NULL

0x0000009a:         DW_TAG_variant
                      DW_AT_discr_value [DW_FORM_data1] (0xff)

0x0000009c:           DW_TAG_member
                        DW_AT_name [DW_FORM_strp]       ("TwoInts")
                        DW_AT_type [DW_FORM_ref4]       (0x000000be "t3::Foo::TwoInts")
                        DW_AT_alignment [DW_FORM_udata] (8)
                        DW_AT_data_member_location [DW_FORM_data1]      (0x00)

0x000000a7:           NULL

0x000000a8:         DW_TAG_variant
                      DW_AT_discr_value [DW_FORM_data1] (0x00)

0x000000aa:           DW_TAG_member
                        DW_AT_name [DW_FORM_strp]       ("ThreeShorts")
                        DW_AT_type [DW_FORM_ref4]       (0x000000dc "t3::Foo::ThreeShorts")
                        DW_AT_alignment [DW_FORM_udata] (8)
                        DW_AT_data_member_location [DW_FORM_data1]      (0x00)

0x000000b5:           NULL

0x000000b6:         NULL

Note that the form for DW_AT_discr_value attribute should not be DW_FORM_dataX, rather it should be DW_FORM_sdata.

Meta

rustc --version --verbose:

rustc 1.74.1 (a28077b28 2023-12-04)
binary: rustc
commit-hash: a28077b28a02b92985b3a3faecf92813155f1ea1
commit-date: 2023-12-04
host: x86_64-unknown-linux-gnu
release: 1.74.1
LLVM version: 17.0.4

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source file or test is identified. Begin by reproducing the two Rust enum examples and tracing rustc's DWARF emission for tagged enums; done means discriminant values, including negative values, use the DWARF-prescribed signed LEB128 representation and the generated forms comply with the standard.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.