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
Confirmed, could reproduce the failure in an ASAN build.
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
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.