Skip to content

Commit

Permalink
Fix crash with empty Rust enum
Browse files Browse the repository at this point in the history
While testing my Rust compiler patch to fix the DWARF representation
of Rust enums (rust-lang/rust#54004), I found
a gdb crash coming from one of the Rust test cases.

The bug here is that the new variant support in gdb does not handle
the case where there are no variants in the enum.

This patch fixes the problem in a straightforward way.  Note that the
new tests are somewhat lax because I did not want to try to fully fix
this corner case for older compilers.  If you think that's
unacceptable, let meknow.

Tested on x86-64 Fedora 28 using several versions of the Rust
compiler.  I intend to push this to the 8.2 branch as well.

gdb/ChangeLog
2018-09-11  Tom Tromey  <tom@tromey.com>

	PR rust/23626:
	* rust-lang.c (rust_enum_variant): Now static.
	(rust_empty_enum_p): New function.
	(rust_print_enum, rust_evaluate_subexp, rust_print_struct_def):
	Handle empty enum.

gdb/testsuite/ChangeLog
2018-09-11  Tom Tromey  <tom@tromey.com>

	PR rust/23626:
	* gdb.rust/simple.rs (EmptyEnum): New type.
	(main): Use it.
	* gdb.rust/simple.exp (test_one_slice): Add empty enum test.
  • Loading branch information
tromey committed Sep 11, 2018
1 parent 849cba3 commit 081ea12
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 1 deletion.
8 changes: 8 additions & 0 deletions gdb/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
2018-09-11 Tom Tromey <tom@tromey.com>

PR rust/23626:
* rust-lang.c (rust_enum_variant): Now static.
(rust_empty_enum_p): New function.
(rust_print_enum, rust_evaluate_subexp, rust_print_struct_def):
Handle empty enum.

2018-09-10 Tom Tromey <tom@tromey.com>

PR python/18380:
Expand Down
42 changes: 41 additions & 1 deletion gdb/rust-lang.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,22 @@ rust_enum_p (const struct type *type)
&& TYPE_FLAG_DISCRIMINATED_UNION (TYPE_FIELD_TYPE (type, 0)));
}

/* Return true if TYPE, which must be an enum type, has no
variants. */

static bool
rust_empty_enum_p (const struct type *type)
{
gdb_assert (rust_enum_p (type));
/* In Rust the enum always fills the containing structure. */
gdb_assert (TYPE_FIELD_BITPOS (type, 0) == 0);

return TYPE_NFIELDS (TYPE_FIELD_TYPE (type, 0)) == 0;
}

/* Given an enum type and contents, find which variant is active. */

struct field *
static struct field *
rust_enum_variant (struct type *type, const gdb_byte *contents)
{
/* In Rust the enum always fills the containing structure. */
Expand Down Expand Up @@ -429,6 +442,13 @@ rust_print_enum (struct type *type, int embedded_offset,

opts.deref_ref = 0;

if (rust_empty_enum_p (type))
{
/* Print the enum type name here to be more clear. */
fprintf_filtered (stream, _("%s {<No data fields>}"), TYPE_NAME (type));
return;
}

const gdb_byte *valaddr = value_contents_for_printing (val);
struct field *variant_field = rust_enum_variant (type, valaddr);
embedded_offset += FIELD_BITPOS (*variant_field) / 8;
Expand Down Expand Up @@ -664,6 +684,18 @@ rust_print_struct_def (struct type *type, const char *varstring,
if (is_enum)
{
fputs_filtered ("enum ", stream);

if (rust_empty_enum_p (type))
{
if (tagname != NULL)
{
fputs_filtered (tagname, stream);
fputs_filtered (" ", stream);
}
fputs_filtered ("{}", stream);
return;
}

type = TYPE_FIELD_TYPE (type, 0);

struct dynamic_prop *discriminant_prop
Expand Down Expand Up @@ -1604,6 +1636,10 @@ rust_evaluate_subexp (struct type *expect_type, struct expression *exp,

if (rust_enum_p (type))
{
if (rust_empty_enum_p (type))
error (_("Cannot access field of empty enum %s"),
TYPE_NAME (type));

const gdb_byte *valaddr = value_contents (lhs);
struct field *variant_field = rust_enum_variant (type, valaddr);

Expand Down Expand Up @@ -1672,6 +1708,10 @@ tuple structs, and tuple-like enum variants"));
type = value_type (lhs);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT && rust_enum_p (type))
{
if (rust_empty_enum_p (type))
error (_("Cannot access field of empty enum %s"),
TYPE_NAME (type));

const gdb_byte *valaddr = value_contents (lhs);
struct field *variant_field = rust_enum_variant (type, valaddr);

Expand Down
7 changes: 7 additions & 0 deletions gdb/testsuite/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
2018-09-11 Tom Tromey <tom@tromey.com>

PR rust/23626:
* gdb.rust/simple.rs (EmptyEnum): New type.
(main): Use it.
* gdb.rust/simple.exp (test_one_slice): Add empty enum test.

2018-09-08 Tom Tromey <tom@tromey.com>

* gdb.python/py-prettyprint.exp: Use with_test_prefix.
Expand Down
12 changes: 12 additions & 0 deletions gdb/testsuite/gdb.rust/simple.exp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,18 @@ gdb_test_sequence "ptype/o SimpleLayout" "" {
" }"
}

# PR rust/23626 - this used to crash. Note that the results are
# fairly lax because most existing versions of Rust (those before the
# DW_TAG_variant patches) do not emit what gdb wants here; and there
# was little point fixing gdb to cope with these cases as the fixed
# compilers will be available soon
gdb_test "print empty_enum_value" \
" = simple::EmptyEnum.*"
gdb_test "ptype empty_enum_value" "simple::EmptyEnum.*"
# Just make sure these don't crash, for the same reason.
gdb_test "print empty_enum_value.0" ""
gdb_test "print empty_enum_value.something" ""

load_lib gdb-python.exp
if {[skip_python_tests]} {
continue
Expand Down
4 changes: 4 additions & 0 deletions gdb/testsuite/gdb.rust/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ struct SimpleLayout {
f2: u16
}

enum EmptyEnum {}

fn main () {
let a = ();
let b : [i32; 0] = [];
Expand Down Expand Up @@ -168,6 +170,8 @@ fn main () {
let u = Union { f2: 255 };
let simplelayout = SimpleLayout { f1: 8, f2: 9 };

let empty_enum_value: EmptyEnum = unsafe { ::std::mem::zeroed() };

println!("{}, {}", x.0, x.1); // set breakpoint here
println!("{}", diff2(92, 45));
empty();
Expand Down

0 comments on commit 081ea12

Please sign in to comment.