Bug 33123 - Out-of-bound memory write in compute_variant_fields_inner
Summary: Out-of-bound memory write in compute_variant_fields_inner
Status: NEW
Alias: None
Product: gdb
Classification: Unclassified
Component: rust (show other bugs)
Version: 16.3
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: 20991
  Show dependency treegraph
 
Reported: 2025-07-02 14:47 UTC by Quentin Sabah
Modified: 2025-07-02 16:31 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build: 2025-07-02 0:00
Last reconfirmed: 2025-07-02 00:00:00
Project(s) to access:
ssh public key:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Quentin Sabah 2025-07-02 14:47:17 UTC
Summary:
GDB 16.3 and HEAD crash with "stack smashing detected" when stepping into a Rust struct method with self having an Option<u128> field.


Steps to Reproduce:
reduced Rust program:
```
    // crash.rs
    struct CrashGdb {
        f: Option<u128>,
    }

    impl CrashGdb {
        fn crash(&self) {
            println!("no crash ? {:?}", self.f);
        }
    }

    fn main() {
        CrashGdb { f: None }.crash(); // Step here
    }
```

Compile and debug:
GDB must be built with stack protector (as in Fedora 41). Or add the gdb_assert as described below in the Diagnosis paragraph.

```
    rustc -g crash.rs
    gdb --args ./crash
```

In GDB:
```
    (gdb) start
    (gdb) step
```

Result:
```
    *** stack smashing detected ***: terminated
```


Diagnosis:
The crash occurs in compute_variant_fields_inner in gdb/gdbtypes.c line 2611 due to a buffer overflow at `read_memory`:
```
    size = type->field (idx).type ()->length ();
    gdb_byte bits[sizeof (ULONGEST)];
    read_memory (addr, bits, size);
```

When stepping into the method, size == 16 but bits[] has only 8 elements. This causes an out-of-bounds write in:
```
    // I added this assertion
    gdb_assert(size <= sizeof(ULONGEST));  // fails: size == 16
    read_memory(addr, bits, size);
``

Stack protector (-fstack-protector) makes the issue immediately fatal, but the overflow exists regardless.



Workaround / Suggested Fix:
Increase the size of the bits buffer:
```
    gdb_byte bits[2 * sizeof (ULONGEST)];
```


This is reproducible with:
- GDB 16.3 (Fedora 41)
  GNU gdb (Fedora Linux) 16.3-1.fc41
  This GDB was configured as "x86_64-redhat-linux-gnu"
- GDB HEAD (commit b054ff604253af016657d5c93e2f69dab14cc53a)
- Crash when GDB compiled with -fstack-protector
- rustc 1.81.0 and 1.85.0
- Kernel:
  Linux workstation 6.15.3-100.fc41.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jun 19 15:09:31 UTC 2025 x86_64 GNU/Linux
Comment 1 Tom Tromey 2025-07-02 15:58:19 UTC
Confirmed, could reproduce the failure in an ASAN build.
Comment 2 Tom Tromey 2025-07-02 16:23:03 UTC
gdb shouldn't crash of course, but I think the fix is more
complicated.

The type in question has a variant part where the discriminant
is 128 bits and so are the associated discriminant values:

 <4><6e1>: Abbrev Number: 33 (DW_TAG_variant_part)
    <6e2>   DW_AT_discr       : <0x6e6>
 <5><6e6>: Abbrev Number: 34 (DW_TAG_member)
    <6e7>   DW_AT_type        : <0x317>
    <6eb>   DW_AT_alignment   : 16
    <6ec>   DW_AT_data_member_location: 0
    <6ed>   DW_AT_artificial  : 1
 <5><6ed>: Abbrev Number: 38 (DW_TAG_variant)
    <6ee>   DW_AT_discr_value : 16 byte block: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
...

So the use of std::optional<ULONGEST> in compute_variant_fields_inner
in insufficient.  And the type will have to store a longer int
for the discriminant value.

This is part of bug #30191
Comment 3 Tom Tromey 2025-07-02 16:28:53 UTC
This one might be simpler than the whole fix for #30191
since variant parts are fairly limited in their impact.
It might not even be terrible to just always store
128-bit integers in struct discriminant_range.