Bug 29735 - Can't have multiple breakpoints - crash otherwise
Summary: Can't have multiple breakpoints - crash otherwise
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: rust (show other bugs)
Version: 12.1
: P2 normal
Target Milestone: 14.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-10-31 13:25 UTC by amir
Modified: 2023-11-24 16:30 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2023-03-08 00:00:00
Project(s) to access:
ssh public key:


Attachments
Patch for this issue, or an issue similar to it (727 bytes, patch)
2023-10-28 18:34 UTC, The Puzzlemaker
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description amir 2022-10-31 13:25:05 UTC
I wrote the following code:

```
use fst::{Set};
use fst::automaton::Levenshtein;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let keys = vec!["hej"];
    let set = Set::from_iter(keys)?;

    let lev = Levenshtein::new("foo", 1)?;

    println!("{:#?}", set);
    println!("{:#?}", lev);
    Ok(())
}
```

This code crashes when attempting to run this line:
```
let lev = Levenshtein::new("foo", 1)?;
```

Here is the `Cargo.toml`:
```
[package]
name = "playground"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
fst = { version = "0.4.7", features = ["levenshtein"] }
```
How to reproduce:
1. `cargo new playground`
2. enter project's root directory
3. `cargo add fst --features=levenshtein`
4. `nvim .` (note: I have NerdTree extension in my Neovim)
5. Navigate into `main.rs` file via NerdTree
6. Replace the `main.rs` content with:
```
use fst::{Set};
use fst::automaton::Levenshtein;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let keys = vec!["hej"];
    let set = Set::from_iter(keys)?;

    let lev = Levenshtein::new("foo", 1)?;

    println!("{:#?}", set);
    println!("{:#?}", lev);
    Ok(())
```
7. `:w` in neovim
8. `:! cargo build` in neovim (note that bash is in project's root folder while neovim is simultaneously in `main.rs` at this point)
9. Open another terminal in project's root folder
10. In the new terminal, run `gdb target/debug/playground` (alternatively: `rust-gdb target/debug/playground`)
11. In gdb, run the following commands, one line at a time (note that I have [GDB Dashboard](https://github.com/cyrus-and/gdb-dashboard) implemented into my GDB):
```
list
b 8 
b 10
list
b 11
b 12
r
c
```
It crashes as soon as you enter `c`. The following specified what "crash" means and shows the output that I see:

```
Breakpoint 2, playground::main () at src/main.rs:10
10	    println!("{:#?}", set);
../../gdb/gdbtypes.h:1064: internal-error: field: Assertion `idx >= 0 && idx < num_fields ()' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
0x5654d0133b6b ???
0x5654d0471d44 ???
0x5654d0534ce3 ???
0x5654d00b3ea1 ???
0x5654d0483e23 ???
0x5654d03b74bc ???
0x5654d047f0db ???
0x5654d0484935 ???
0x5654d0485b6b ???
0x5654d03b70ab ???
0x5654d047f0db ???
0x5654d03b6cd0 ???
0x5654d03b70ef ???
0x5654d047f0db ???
0x5654d036ed08 ???
0x7f96c5548418 ???
0x7f96c54f9c9f ???
0x7f96c54f4b83 ???
0x7f96c5529420 ???
0x7f96c54e4b33 ???
0x5654d03632a6 ???
0x5654d022a526 ???
0x5654d047f164 ???
0x5654d03b6cd0 ???
0x5654d03b70ef ???
0x5654d047f0db ???
0x5654d03b6cd0 ???
0x5654d03b70ef ???
0x5654d047f0db ???
0x5654d036ed08 ???
0x7f96c5548418 ???
0x7f96c54f9c9f ???
0x7f96c54f4b83 ???
0x7f96c5500bb8 ???
0x7f96c54efd75 ???
0x7f96c5500bb8 ???
0x7f96c54efd75 ???
0x7f96c5500bb8 ???
0x7f96c54f48de ???
0x7f96c5500bb8 ???
0x7f96c54f48de ???
0x7f96c5500bb8 ???
0x7f96c54f01a9 ???
0x7f96c550be45 ???
0x7f96c54f0eb5 ???
0x7f96c54ee9bf ???
0x7f96c550bf6c ???
0x7f96c5500357 ???
0x7f96c559dcc0 ???
0x5654d05b11ba ???
0x5654d03617f2 ???
0x5654d02bc432 ???
0x5654d02b3f52 ???
0x5654d0535955 ???
0x5654d0535d06 ???
0x5654d02f3d24 ???
0x5654d009fc04 ???
0x7f96c4c3a28f ???
0x7f96c4c3a349 ???
0x5654d00a61e4 ???
0xffffffffffffffff ???
---------------------
../../gdb/gdbtypes.h:1064: internal-error: field: Assertion `idx >= 0 && idx < num_fields ()' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) 

```
Comment 1 Tom Tromey 2022-10-31 20:21:26 UTC
This works for me.  I tried the gdb 12 release branch and also git master.

Can you try reproducing with '-nx' -- that is, avoid your add-ons?
Comment 2 amir 2022-11-01 03:37:39 UTC
(In reply to Tom Tromey from comment #1)
> This works for me.  I tried the gdb 12 release branch and also git master.
> 
> Can you try reproducing with '-nx' -- that is, avoid your add-ons?

Oh, it works for me now that I used `-nx`. Thanks
Comment 3 Tom Tromey 2022-11-01 13:38:11 UTC
This doesn't mean there isn't a gdb bug.
Maybe gdb-dashboard is running other commands behind the scenes.
It would be good to find out.
Comment 4 amir 2022-11-01 14:27:26 UTC
(In reply to Tom Tromey from comment #3)
> This doesn't mean there isn't a gdb bug.
> Maybe gdb-dashboard is running other commands behind the scenes.
> It would be good to find out.

Any suggestions on specific steps I may try out?
Comment 5 Tom Tromey 2022-11-02 19:47:40 UTC
(In reply to amir from comment #4)

> Any suggestions on specific steps I may try out?

I don't know much about gdb-dashboard, so I don't know what to suggest.
Based on the assertion, I'd say maybe try "info local" at the
second breakpoint.  Otherwise maybe see if gdb-dashboard has some
kind of verbose mode or the like.
Comment 6 Tom Tromey 2023-03-08 00:28:58 UTC
Any new info on this?
Comment 7 The Puzzlemaker 2023-10-28 18:34:28 UTC
Created attachment 15198 [details]
Patch for this issue, or an issue similar to it

I experienced this in 13.2. I believe it's related to the null pointer optimization, or at least the case I encountered was.

```
use std::num::NonZeroUsize;
use std::hint::black_box;

pub fn main() {
    foo(black_box(NonZeroUsize::new(5)), black_box(NonZeroUsize::new(5)))
}

#[inline(never)]
pub fn foo(x: Option<NonZeroUsize>, y: Option<NonZeroUsize>) {
    black_box(x.unwrap().checked_add(y.unwrap().into()));
}
```

Put this in `tmp.rs`.
Compile with `rustc tmp.rs -Copt-level=1 -Cdebuginfo=full`
Run `gdb tmp::foo`
`break foo`
`run`
`info args`

Observe assertion fail:
```
x = core::option::Option<core::num::nonzero::NonZeroUsize>::Some(
../../gdb/gdbtypes.h:985: internal-error: field: Assertion `idx >= 0 && idx < num_fields ()' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
```

This issue is related to this portion of code in `rust_lang::print_enum`:
```
 461   type = resolve_dynamic_type (type, view, value_address (val));
 ...   [snip]
 472   int variant_fieldno = rust_enum_variant (type);
 473   val = value_field (val, variant_fieldno);
 474   struct type *variant_type = type->field (variant_fieldno).type ();
```
https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/rust-lang.c;h=74808ad0716e4d67f6af859f05ebff2b55d5e276;hb=662243de0e14a4945555a480dca33c0e677976eb#l461
The type from `resolve_dynamic_type` makes only the variant field of the active discriminant in active. However, the type of `val` has *all* variant fields enabled, thus making this index meaningless for that. I created a patch for this, which is somewhat hacky--any maintainers here, feel free to change it up a bit; I am a Rust developer by nature and don't know much about idiomatic C/++ and in general, what the GDB codebase looks like.

Please let me know if you'd like me to test/update this patch to the v14 codebase.
Comment 8 The Puzzlemaker 2023-10-28 18:51:22 UTC
Woops, I apologize, I accidentally left a debugging `printf` in there. Give me a moment and I'll upload the real patch
Comment 9 The Puzzlemaker 2023-10-28 18:55:13 UTC
Comment on attachment 15198 [details]
Patch for this issue, or an issue similar to it

>From 07bb370168aab780c4780435ad3d9257ad8a474b Mon Sep 17 00:00:00 2001
>From: ThePuzzlemaker <tpzker@thepuzzlemaker.info>
>Date: Sat, 28 Oct 2023 13:28:33 -0500
>Subject: [PATCH] Fix assertion fail from `rust_lang::print_enum`
>
>This commit fixes an assertion fail in `rust_lang::print_enum` related
>to the handling of field numbers for variant types.
>---
> gdb/rust-lang.c | 12 +++++++++++-
> 1 file changed, 11 insertions(+), 1 deletion(-)
>
>diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
>index 74808ad0716..9acd2e1d2fa 100644
>--- a/gdb/rust-lang.c
>+++ b/gdb/rust-lang.c
>@@ -470,8 +470,18 @@ rust_language::print_enum (struct value *val, struct ui_file *stream,
>     }
> 
>   int variant_fieldno = rust_enum_variant (type);
>-  val = value_field (val, variant_fieldno);
>   struct type *variant_type = type->field (variant_fieldno).type ();
>+  /* HACK: variant_fieldno is indexed in 'type', which has the field
>+     disabled for other variants. The type of 'val' does not. Thus,
>+     iterate through the fields and find the one that matches. */
>+  for (int i = 0; i < value_type (val)->num_fields (); i++) {
>+    value* new_val = value_field (val, i);
>+    if (types_equal (value_type (new_val), variant_type)) {
>+      val = new_val;
>+      break;
>+    }
>+  }
>+  gdb_assert(types_equal(value_type (val), variant_type));
> 
>   int nfields = variant_type->num_fields ();
> 
>-- 
>2.42.0
Comment 10 Tom Tromey 2023-10-28 20:46:11 UTC
(In reply to The Puzzlemaker from comment #9)
> Comment on attachment 15198 [details]
> Patch for this issue, or an issue similar to it
> 
> >From 07bb370168aab780c4780435ad3d9257ad8a474b Mon Sep 17 00:00:00 2001
> >From: ThePuzzlemaker <tpzker@thepuzzlemaker.info>
> >Date: Sat, 28 Oct 2023 13:28:33 -0500
> >Subject: [PATCH] Fix assertion fail from `rust_lang::print_enum`
> >
> >This commit fixes an assertion fail in `rust_lang::print_enum` related
> >to the handling of field numbers for variant types.
> >---
> > gdb/rust-lang.c | 12 +++++++++++-
> > 1 file changed, 11 insertions(+), 1 deletion(-)
> >
> >diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
> >index 74808ad0716..9acd2e1d2fa 100644
> >--- a/gdb/rust-lang.c
> >+++ b/gdb/rust-lang.c
> >@@ -470,8 +470,18 @@ rust_language::print_enum (struct value *val, struct ui_file *stream,
> >     }
> > 
> >   int variant_fieldno = rust_enum_variant (type);
> >-  val = value_field (val, variant_fieldno);

This code looks different on trunk.
IIRC I fixed a bug like this a while ago.
git says 2020 though, which seems wrong if you're using 13.
Comment 11 Tom Tromey 2023-10-28 20:48:18 UTC
(In reply to The Puzzlemaker from comment #7)

> `break foo`
> `run`
> `info args`

This works for me with my 14.x build from git:

(gdb) info args
x = core::option::Option<core::num::nonzero::NonZeroUsize>::Some(core::num::nonzero::NonZeroUsize (
    5
  ))
y = core::option::Option<core::num::nonzero::NonZeroUsize>::Some(core::num::nonzero::NonZeroUsize (
    5
  ))
Comment 12 The Puzzlemaker 2023-10-28 20:56:28 UTC
This is in fact fixed in 14.x git.
Comment 14 The Puzzlemaker 2023-10-28 21:08:38 UTC
Thanks for your help. @amir, it'd be great if you could test and see if this issue still occurs with GDB 14.x
Comment 15 Tom Tromey 2023-11-24 16:30:11 UTC
I think this is fixed.