[PATCH 2/3] gdb: avoid dereferencing empty str_offsets_base optional in dwarf_decode_macros

Simon Marchi simon.marchi@polymtl.ca
Tue Aug 3 15:31:13 GMT 2021


Since 4d7188abfdf2 ("gdbsupport: add debug assertions in
gdb::optional::get"), some macro-related tests fail on Ubuntu 20.04 with
the system gcc 9.3.0 compiler when building with _GLIBCXX_DEBUG.  For
example, gdb.base/info-macros.exp results in:

   (gdb) break -qualified main
   /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/gdb_optional.h:206: internal-error: T& gdb::optional<T>::get() [with T = long unsigned int]: Assertion `this->has_value ()' failed.

The binary contains DWARF 4 debug info and includes a pre-standard
(pre-DWARF 5) .debug_macro section.  The CU doesn't have a
DW_AT_str_offsets_base attribute (which doesn't exist in DWARF 4).  The
field dwarf2_cu::str_offsets_base is therefore empty.  At
dwarf2/read.c:24138, we unconditionally read the value in the optional,
which triggers the assertion shown above.

The same thing happens when building the test program with DWARF 5 with
the same gcc compiler, as that version of gcc doesn't use indirect
string forms, even with DWARF 5.  So it still doesn't add a
DW_AT_str_offsets_base attribute on the CU.

Fix that by propagating down a gdb::optional<ULONGEST> for the str
offsets base instead of ULONGEST.  That value is only used in
dwarf_decode_macro_bytes, when encountering an "strx" macro operation
(DW_MACRO_define_strx or DW_MACRO_undef_strx).  Add a check there that
we indeed have a value in the optional before reading it.  This is
unlikely to happen, but could happen in theory with an erroneous file
that uses DW_MACRO_define_strx but does not provide a
DW_AT_str_offsets_base (in practice, some things would probably have
failed before and stopped processing of debug info).  I tested the
complaint by inverting the condition and using a clang-compiled binary,
which uses the strx operators.  This is the result:

    During symbol reading: use of DW_MACRO_define_strx with unknown string offsets base [in module /home/simark/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/info-macros/info-macros]

The test now passes cleanly with the setup mentioned above, and the
testsuite looks on par with how it was before 4d7188abfdf2.

Change-Id: I7ebd2724beb7b9b4178872374c2a177aea696e77
---
 gdb/dwarf2/macro.c | 21 +++++++++++++++++----
 gdb/dwarf2/macro.h |  2 +-
 gdb/dwarf2/read.c  |  4 ++--
 3 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/gdb/dwarf2/macro.c b/gdb/dwarf2/macro.c
index bf687daedd71..082c4e9672ae 100644
--- a/gdb/dwarf2/macro.c
+++ b/gdb/dwarf2/macro.c
@@ -429,7 +429,7 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
 			  unsigned int offset_size,
 			  struct dwarf2_section_info *str_section,
 			  struct dwarf2_section_info *str_offsets_section,
-			  ULONGEST str_offsets_base,
+			  gdb::optional<ULONGEST> str_offsets_base,
 			  htab_t include_hash)
 {
   struct objfile *objfile = per_objfile->objfile;
@@ -575,15 +575,27 @@ dwarf_decode_macro_bytes (dwarf2_per_objfile *per_objfile,
 	    int offset_index = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read);
 	    mac_ptr += bytes_read;
 
+	    /* Use of the strx operators requires a DW_AT_str_offsets_base.  */
+	    if (!str_offsets_base.has_value ())
+	      {
+		complaint (_("use of %s with unknown string offsets base "
+			     "[in module %s]"),
+			   (macinfo_type == DW_MACRO_define_strx
+			    ? "DW_MACRO_define_strx"
+			    : "DW_MACRO_undef_strx"),
+			   objfile_name (objfile));
+		break;
+	      }
+
 	    str_offsets_section->read (objfile);
 	    const gdb_byte *info_ptr = (str_offsets_section->buffer
-					+ str_offsets_base
+					+ *str_offsets_base
 					+ offset_index * offset_size);
 
 	    const char *macinfo_str = (macinfo_type == DW_MACRO_define_strx ?
 				       "DW_MACRO_define_strx" : "DW_MACRO_undef_strx");
 
-	    if (str_offsets_base + offset_index * offset_size
+	    if (*str_offsets_base + offset_index * offset_size
 		>= str_offsets_section->size)
 	      {
 		complaint (_("%s pointing outside of .debug_str_offsets section "
@@ -767,7 +779,8 @@ dwarf_decode_macros (dwarf2_per_objfile *per_objfile,
 		     const struct line_header *lh, unsigned int offset_size,
 		     unsigned int offset, struct dwarf2_section_info *str_section,
 		     struct dwarf2_section_info *str_offsets_section,
-		     ULONGEST str_offsets_base, int section_is_gnu)
+		     gdb::optional<ULONGEST> str_offsets_base,
+		     int section_is_gnu)
 {
   bfd *abfd;
   const gdb_byte *mac_ptr, *mac_end;
diff --git a/gdb/dwarf2/macro.h b/gdb/dwarf2/macro.h
index 5e77c913cadd..5a0539231249 100644
--- a/gdb/dwarf2/macro.h
+++ b/gdb/dwarf2/macro.h
@@ -30,7 +30,7 @@ extern void dwarf_decode_macros (dwarf2_per_objfile *per_objfile,
 				 unsigned int offset,
 				 dwarf2_section_info *str_section,
 				 dwarf2_section_info *str_offsets_section,
-				 ULONGEST str_offsets_base,
+				 gdb::optional<ULONGEST> str_offsets_base,
 				 int section_is_gnu);
 
 #endif /* GDB_DWARF2_MACRO_H */
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 6f1b453ef455..acabee3315f8 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -24122,7 +24122,7 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset,
 
   struct dwarf2_section_info *str_offsets_section;
   struct dwarf2_section_info *str_section;
-  ULONGEST str_offsets_base;
+  gdb::optional<ULONGEST> str_offsets_base;
 
   if (cu->dwo_unit != nullptr)
     {
@@ -24135,7 +24135,7 @@ dwarf_decode_macros (struct dwarf2_cu *cu, unsigned int offset,
     {
       str_offsets_section = &per_objfile->per_bfd->str_offsets;
       str_section = &per_objfile->per_bfd->str;
-      str_offsets_base = *cu->str_offsets_base;
+      str_offsets_base = cu->str_offsets_base;
     }
 
   dwarf_decode_macros (per_objfile, builder, section, lh,
-- 
2.32.0



More information about the Gdb-patches mailing list