[v2] gdb/dwarf: fix assert failed for missing containing type

Message ID 20251223112053.1157679-1-liuke.gehry@bytedance.com
State New
Headers
Series [v2] gdb/dwarf: fix assert failed for missing containing type |

Commit Message

Sockke Dec. 23, 2025, 11:20 a.m. UTC
  This patch fixes an assertion failure that occurs when handling missing type units.
If the TU referenced by a `DW_AT_containing_type` cannot be found (e.g., due to DWP overflow), the error type returned from the DWARF reader is incorrectly passed to `set_type_vptr_fieldno`, causing an assertion failure:
gdb/gdbtypes.c:1919: internal-error: internal_type_vptr_fieldno: Assertion `type->code () == TYPE_CODE_STRUCT || type->code () == TYPE_CODE_UNION' failed.

Signed-off-by: Sockke <liuke.gehry@bytedance.com>
---
 gdb/dwarf2/read.c                             |  6 +-
 .../gdb.dwarf2/missing-containing-type.exp    | 71 +++++++++++++++++++
 2 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/missing-containing-type.exp
  

Comments

Andrew Burgess Dec. 23, 2025, 4:37 p.m. UTC | #1
Hi,

Thanks for looking at this issue.

"Sockke" <liuke.gehry@bytedance.com> writes:

> This patch fixes an assertion failure that occurs when handling missing type units.
> If the TU referenced by a `DW_AT_containing_type` cannot be found (e.g., due to DWP overflow), the error type returned from the DWARF reader is incorrectly passed to `set_type_vptr_fieldno`, causing an assertion failure:
> gdb/gdbtypes.c:1919: internal-error: internal_type_vptr_fieldno: Assertion `type->code () == TYPE_CODE_STRUCT || type->code () == TYPE_CODE_UNION' failed.

Please format commit message to somewhere around 72 to 76 characters
where possible.  It's OK though if error message are faithfully
reproduced, and are longer than this.  For example, this is much more
readable:

    gdb/dwarf: fix assert failed for missing containing type
    
    This patch fixes an assertion failure that occurs when handling
    missing type units.
    
    If the TU referenced by a `DW_AT_containing_type` cannot be
    found (e.g., due to DWP overflow), the error type returned from the
    DWARF reader is incorrectly passed to `set_type_vptr_fieldno`, causing
    an assertion failure:
    
      gdb/gdbtypes.c:1919: internal-error: internal_type_vptr_fieldno: Assertion `type->code () == TYPE_CODE_STRUCT || type->code () == TYPE_CODE_UNION' failed.

>
> Signed-off-by: Sockke <liuke.gehry@bytedance.com>

Please don't add Signed-off-by tags to GDB commits, these have no
meaning for this project, but might do in the future.  See
gdb/MAINTAINERS for a list of tags that are relevant to this project.

> ---
>  gdb/dwarf2/read.c                             |  6 +-
>  .../gdb.dwarf2/missing-containing-type.exp    | 71 +++++++++++++++++++
>  2 files changed, 76 insertions(+), 1 deletion(-)
>  create mode 100644 gdb/testsuite/gdb.dwarf2/missing-containing-type.exp
>
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index 4e2644ba..eadd56b7 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -11525,7 +11525,11 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
>  	      struct type *t = die_containing_type (die, cu);
>  
>  	      set_type_vptr_basetype (type, t);
> -	      if (type == t)
> +	      if (t->code() == TYPE_CODE_ERROR)

Reading the test, could it not be possible that badly formed debug
information might mean that die_containing_type does returned a type,
but that type is NOT a struct or a union?

I wonder if instead of checking for TYPE_CODE_ERROR here, if we should
instead do:

  if (type == t)
    {
      ... existing code ...
    }
  else if (type->code () == TYPE_CODE_STRUCT
           || type->code () == TYPE_CODE_UNION)
    set_type_vptr_fieldno (type, TYPE_VPTR_FIELDNO (t));
  else
    complaint (...);

> +		{
> +		  complaint (_("%s"), TYPE_ERROR_NAME (t));

It might be nice to have a more descriptive complaint here.

> +		}
> +	      else if (type == t)
>  		{
>  		  int i;
>  
> diff --git a/gdb/testsuite/gdb.dwarf2/missing-containing-type.exp b/gdb/testsuite/gdb.dwarf2/missing-containing-type.exp
> new file mode 100644
> index 00000000..8e9a1563
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/missing-containing-type.exp
> @@ -0,0 +1,71 @@
> +# Copyright 2013-2025 Free Software Foundation, Inc.

Unless this test has been distributed elsewhere since 2013, the
copyright date should probably be just 2025.

> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +load_lib dwarf.exp
> +
> +# This test can only be run on targets which support DWARF-2 and use gas.
> +require dwarf2_support
> +
> +require allow_cplus_tests
> +
> +standard_testfile main.c -dw4.S
> +
> +# Make some DWARF for the test.
> +set asm_file [standard_output_file $srcfile2]
> +Dwarf::assemble $asm_file {
> +    cu {} {
> +       DW_TAG_compile_unit {
> +           DW_AT_language @DW_LANG_C_plus_plus
> +       } {
> +           declare_labels container_decl abase_client_type
> +           DW_TAG_namespace {
> +               DW_AT_name NS
> +           } {
> +               container_decl: DW_TAG_class_type {
> +                   DW_AT_signature     0x1122334455667788 DW_FORM_ref_sig8
> +                   DW_AT_declaration   1                  DW_FORM_flag
> +               } {
> +                   abase_client_type: DW_TAG_class_type {
> +                       DW_AT_name           C
> +                       DW_AT_byte_size      0x170              DW_FORM_sdata
> +                       DW_AT_containing_type :$container_decl
> +                   } {
> +                       DW_TAG_subprogram { DW_AT_name "~C" }
> +                   }
> +               }
> +           }
> +       }
> +    }
> +    # The referenced TU has been lost.
> +    #tu {} 0x1122334455667788 container_type {
> +    #   DW_TAG_type_unit {
> +    #       DW_AT_language @DW_LANG_C_plus_plus
> +    #   } {
> +    #       DW_AT_container_type: class_type {
> +    #           {DW_AT_name C}
> +    #           {DW_AT_byte_size 1 sdata}
> +    #       }
> +    #   }
> +    #}
> +}
> +
> +
> +if { [prepare_for_testing "failed to prepare" ${testfile} \
> +	  [list $srcfile $asm_file] {nodebug}] } {
> +    return -1

The -1 here is not needed.

Thanks,
Andrew

> +}
> +
> +gdb_test_no_output "set language c++"
> +
> +gdb_test "ptype NS::C" "No symbol .*"
> -- 
> 2.20.1
  

Patch

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 4e2644ba..eadd56b7 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -11525,7 +11525,11 @@  process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
 	      struct type *t = die_containing_type (die, cu);
 
 	      set_type_vptr_basetype (type, t);
-	      if (type == t)
+	      if (t->code() == TYPE_CODE_ERROR)
+		{
+		  complaint (_("%s"), TYPE_ERROR_NAME (t));
+		}
+	      else if (type == t)
 		{
 		  int i;
 
diff --git a/gdb/testsuite/gdb.dwarf2/missing-containing-type.exp b/gdb/testsuite/gdb.dwarf2/missing-containing-type.exp
new file mode 100644
index 00000000..8e9a1563
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/missing-containing-type.exp
@@ -0,0 +1,71 @@ 
+# Copyright 2013-2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+require dwarf2_support
+
+require allow_cplus_tests
+
+standard_testfile main.c -dw4.S
+
+# Make some DWARF for the test.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu {} {
+       DW_TAG_compile_unit {
+           DW_AT_language @DW_LANG_C_plus_plus
+       } {
+           declare_labels container_decl abase_client_type
+           DW_TAG_namespace {
+               DW_AT_name NS
+           } {
+               container_decl: DW_TAG_class_type {
+                   DW_AT_signature     0x1122334455667788 DW_FORM_ref_sig8
+                   DW_AT_declaration   1                  DW_FORM_flag
+               } {
+                   abase_client_type: DW_TAG_class_type {
+                       DW_AT_name           C
+                       DW_AT_byte_size      0x170              DW_FORM_sdata
+                       DW_AT_containing_type :$container_decl
+                   } {
+                       DW_TAG_subprogram { DW_AT_name "~C" }
+                   }
+               }
+           }
+       }
+    }
+    # The referenced TU has been lost.
+    #tu {} 0x1122334455667788 container_type {
+    #   DW_TAG_type_unit {
+    #       DW_AT_language @DW_LANG_C_plus_plus
+    #   } {
+    #       DW_AT_container_type: class_type {
+    #           {DW_AT_name C}
+    #           {DW_AT_byte_size 1 sdata}
+    #       }
+    #   }
+    #}
+}
+
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+	  [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+gdb_test_no_output "set language c++"
+
+gdb_test "ptype NS::C" "No symbol .*"