]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Fix crash with empty Rust enum
authorTom Tromey <tom@tromey.com>
Tue, 11 Sep 2018 21:28:04 +0000 (15:28 -0600)
committerTom Tromey <tom@tromey.com>
Thu, 13 Sep 2018 17:02:50 +0000 (11:02 -0600)
While testing my Rust compiler patch to fix the DWARF representation
of Rust enums (https://github.com/rust-lang/rust/pull/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.

2018-09-13  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-13  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.

gdb/ChangeLog
gdb/rust-lang.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.rust/simple.exp
gdb/testsuite/gdb.rust/simple.rs

index a454307c61a2dcfa901cf7b8aff58d685f6be380..f989489263b4753950c5e863ae9342fccef78bc0 100644 (file)
@@ -1,3 +1,11 @@
+2018-09-13  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  Eli Zaretskii  <eliz@gnu.org>
 
        * Makefile.in (transformed_name): Use INSTALL_SCRIPT instead of
index 5f4aceb86ba91949ff2f8ce2293698e2b068956a..b72e0e4e4d9906fd382d41287bc96492468c6769 100644 (file)
@@ -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.  */
@@ -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;
@@ -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
@@ -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 %d of empty enum %s"),
+                        field_number, TYPE_NAME (type));
+
                const gdb_byte *valaddr = value_contents (lhs);
                struct field *variant_field = rust_enum_variant (type, valaddr);
 
@@ -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 %s of empty enum %s"),
+                    field_name, TYPE_NAME (type));
+
            const gdb_byte *valaddr = value_contents (lhs);
            struct field *variant_field = rust_enum_variant (type, valaddr);
 
index 35173f0df58b4251e5d7e199c03fa99956576807..3df7668547aafb77c51b9cafe34e9385cc596cc8 100644 (file)
@@ -1,3 +1,10 @@
+2018-09-13  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-08-31  Tom Tromey  <tom@tromey.com>
 
        * gdb.rust/simple.rs: Rename second variable "v".
index 20fe8dd0a882ee798010ffbf466f67672b93731f..07b25122200c804bb3a536bc83c016f1ede33e78 100644 (file)
@@ -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
index 1bcc030d608cfc9d9844f88a684d0261b641019c..00a25e0828dd8cc204a97e062ea081e5b265daeb 100644 (file)
@@ -92,6 +92,8 @@ struct SimpleLayout {
     f2: u16
 }
 
+enum EmptyEnum {}
+
 fn main () {
     let a = ();
     let b : [i32; 0] = [];
@@ -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();