PR 33637, abort in byte_get

Message ID aSu6fXYLf20FZ08a@squeak.grove.modra.org
State New
Headers
Series PR 33637, abort in byte_get |

Commit Message

Alan Modra Nov. 30, 2025, 3:31 a.m. UTC
  When DWARF5 support was added to binutils in commit 77145576fadc,
the loop over CUs in process_debug_info set do_types when finding a
DW_UT_type unit, in order to process the signature and type offset
entries.  Unfortunately that broke debug_information/debug_info_p
handling, which previously was allocated and initialised for each unit
in .debug_info.  debug_info_p was NULL when processing a DWARF4
.debug_types section.  After the 77145576fadc change it was possible
for debug_infp_p to be non-NULL but point to zeroed data, in
particular a zeroed offset_size.  A zero for offset_size led to the
byte_get_little_endian abort triggered by the fuzzer testcase.

I haven't investigated whether there is any need for a valid
offset_size when processing a non-fuzzed DWARF4 .debug_types section.
Presumably we'd have found that out in the last 6 years if that was
the case.  We don't want to change debug_information[] for
.debug_types!

	PR 33637
	* dwarf.c (process_debug_info): Don't change DO_TYPES flag bit
	depending on cu_unit_type.  Instead test cu_unit_type along
	with DO_TYPES to handle signature and type_offset for a type
	unit.  Move find_cu_tu_set_v2 call a little later.
  

Patch

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index e10e33095db..2659f25e179 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -3891,8 +3891,6 @@  process_debug_info (struct dwarf_section * section,
 
       SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu);
 
-      this_set = find_cu_tu_set_v2 (cu_offset, (do_flags & DO_TYPES));
-
       if (compunit.cu_version < 5)
 	{
 	  compunit.cu_unit_type = DW_UT_compile;
@@ -3902,11 +3900,6 @@  process_debug_info (struct dwarf_section * section,
       else
 	{
 	  SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu);
-	  if (compunit.cu_unit_type == DW_UT_type)
-	    do_flags |= DO_TYPES;
-	  else
-	    do_flags &= ~DO_TYPES;
-
 	  SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end_cu);
 	}
 
@@ -3920,6 +3913,7 @@  process_debug_info (struct dwarf_section * section,
 	  SAFE_BYTE_GET_AND_INC (dwo_id, hdrptr, 8, end_cu);
 	}
 
+      this_set = find_cu_tu_set_v2 (cu_offset, (do_flags & DO_TYPES));
       if (this_set == NULL)
 	{
 	  abbrev_base = 0;
@@ -3976,8 +3970,6 @@  process_debug_info (struct dwarf_section * section,
 
       SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu);
 
-      this_set = find_cu_tu_set_v2 (cu_offset, (do_flags & DO_TYPES));
-
       if (compunit.cu_version < 5)
 	{
 	  compunit.cu_unit_type = DW_UT_compile;
@@ -3987,16 +3979,12 @@  process_debug_info (struct dwarf_section * section,
       else
 	{
 	  SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu);
-	  if (compunit.cu_unit_type == DW_UT_type)
-	    do_flags |= DO_TYPES;
-	  else
-	    do_flags &= ~DO_TYPES;
-
 	  SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end_cu);
 	}
 
       SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end_cu);
 
+      this_set = find_cu_tu_set_v2 (cu_offset, (do_flags & DO_TYPES));
       if (this_set == NULL)
 	{
 	  abbrev_base = 0;
@@ -4028,7 +4016,7 @@  process_debug_info (struct dwarf_section * section,
 	  compunit.cu_pointer_size = offset_size;
 	}
 
-      if (do_flags & DO_TYPES)
+      if ((do_flags & DO_TYPES) || compunit.cu_unit_type == DW_UT_type)
 	{
 	  SAFE_BYTE_GET_AND_INC (signature, hdrptr, 8, end_cu);
 	  SAFE_BYTE_GET_AND_INC (type_offset, hdrptr, offset_size, end_cu);
@@ -4044,7 +4032,7 @@  process_debug_info (struct dwarf_section * section,
 	  || do_debug_ranges || do_debug_info)
 	  && num_debug_info_entries == 0
 	  && alloc_num_debug_info_entries > unit
-	  && ! (do_flags & DO_TYPES))
+	  && !(do_flags & DO_TYPES))
 	{
 	  free_debug_information (&debug_information[unit]);
 	  memset (&debug_information[unit], 0, sizeof (*debug_information));
@@ -4075,7 +4063,7 @@  process_debug_info (struct dwarf_section * section,
 	  printf (_("   Abbrev Offset: %#" PRIx64 "\n"),
 		  compunit.cu_abbrev_offset);
 	  printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
-	  if (do_flags & DO_TYPES)
+	  if ((do_flags & DO_TYPES) || compunit.cu_unit_type == DW_UT_type)
 	    {
 	      printf (_("   Signature:     %#" PRIx64 "\n"), signature);
 	      printf (_("   Type Offset:   %#" PRIx64 "\n"), type_offset);
@@ -4350,7 +4338,7 @@  process_debug_info (struct dwarf_section * section,
      we need to process .debug_loc and .debug_ranges sections.  */
   if (((do_flags & DO_LOC) || do_debug_loc || do_debug_ranges || do_debug_info)
       && num_debug_info_entries == 0
-      && ! (do_flags & DO_TYPES))
+      && !(do_flags & DO_TYPES))
     {
       if (num_units > alloc_num_debug_info_entries)
 	num_debug_info_entries = alloc_num_debug_info_entries;