[binutils-gdb] gdb/bfd: avoid crash when architecture is forced to csky or riscv

Andrew Burgess aburgess@sourceware.org
Thu May 20 12:44:30 GMT 2021


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=427e4066afd13d1bf52c849849475f536e285d66

commit 427e4066afd13d1bf52c849849475f536e285d66
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Thu May 20 09:16:41 2021 +0100

    gdb/bfd: avoid crash when architecture is forced to csky or riscv
    
    I built GDB with `--enable-targets=all`, then started GDB passing it
    an x86-64 executable, finally I ran 'maint selftest', and observed GDB
    crash like this:
    
      BFD: BFD (GNU Binutils) 2.36.50.20210519 assertion fail ../../src/bfd/hash.c:438
      Aborted (core dumped)
    
    The problem originates from two locations, for example in csky-dis.c
    (csky_get_disassembler) where we do this:
    
      const char *sec_name = NULL;
      ...
      sec_name = get_elf_backend_data (abfd)->obj_attrs_section;
      if (bfd_get_section_by_name (abfd, sec_name) != NULL)
        ...
    
    We end up in here because during the selftests GDB forces the
    architecture to be csky, but the BFD being accessed is still of type
    x86-64.  As a result obj_attrs_section returns NULL, which means we
    end up passing NULL to bfd_get_section_by_name.  If we follow the
    function calls from bfd_get_section_by_name we eventually end up in
    bfd_hash_hash, which asserts that the string (i.e. the name) is not
    NULL.
    
    The same crash can be reproduced in GDB without using the selftests,
    for example:
    
      (gdb) file x86_64.elf
      (gdb) start
      (gdb) set architecture csky
      (gdb) disassemble main
      Dump of assembler code for function main:
      BFD: BFD (GNU Binutils) 2.36.50.20210519 assertion fail ../../src/bfd/hash.c:438
      Aborted (core dumped)
    
    The fix I propose here is to have bfd_get_section_by_name return NULL
    if name is ever NULL.  For consistency I updated
    bfd_get_section_by_name_if in the same way, even though I'm not
    hitting any problems along that code path right now.
    
    I looked through the source tree and removed two NULL checks in
    bfd/dwarf2.c which are no longer needed, its possible that there are
    additional NULL checks that could be removed, I just didn't find them.
    
    bfd/ChangeLog:
    
            * section.c (bfd_get_section_by_name): Return NULL if name is
            NULL.
            (bfd_get_section_by_name_if): Likewise.
            * dwarf2.c (read_section): Remove unneeded NULL check.
            (find_debug_info): Likewise.

Diff:
---
 bfd/ChangeLog |  8 ++++++++
 bfd/dwarf2.c  | 12 ++++--------
 bfd/section.c |  6 ++++++
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index a389fdfc8b1..2ad78033015 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,11 @@
+2021-05-20  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* section.c (bfd_get_section_by_name): Return NULL if name is
+	NULL.
+	(bfd_get_section_by_name_if): Likewise.
+	* dwarf2.c (read_section): Remove unneeded NULL check.
+	(find_debug_info): Likewise.
+
 2021-05-19  Nick Clifton  <nickc@redhat.com>
 
 	* plugin.c (bfd_plugin_open_input): Inform the user if the limit
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index 0a8a5578da8..cf1f1d1f1ff 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -545,8 +545,7 @@ read_section (bfd *	      abfd,
       if (msec == NULL)
 	{
 	  section_name = sec->compressed_name;
-	  if (section_name != NULL)
-	    msec = bfd_get_section_by_name (abfd, section_name);
+          msec = bfd_get_section_by_name (abfd, section_name);
 	}
       if (msec == NULL)
 	{
@@ -4226,12 +4225,9 @@ find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections,
 	return msec;
 
       look = debug_sections[debug_info].compressed_name;
-      if (look != NULL)
-	{
-	  msec = bfd_get_section_by_name (abfd, look);
-	  if (msec != NULL)
-	    return msec;
-	}
+      msec = bfd_get_section_by_name (abfd, look);
+      if (msec != NULL)
+        return msec;
 
       for (msec = abfd->sections; msec != NULL; msec = msec->next)
 	if (startswith (msec->name, GNU_LINKONCE_INFO))
diff --git a/bfd/section.c b/bfd/section.c
index a35348833d9..6b6aa92b968 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -898,6 +898,9 @@ bfd_get_section_by_name (bfd *abfd, const char *name)
 {
   struct section_hash_entry *sh;
 
+  if (name == NULL)
+    return NULL;
+
   sh = section_hash_lookup (&abfd->section_htab, name, false, false);
   if (sh != NULL)
     return &sh->section;
@@ -1006,6 +1009,9 @@ bfd_get_section_by_name_if (bfd *abfd, const char *name,
   struct section_hash_entry *sh;
   unsigned long hash;
 
+  if (name == NULL)
+    return NULL;
+
   sh = section_hash_lookup (&abfd->section_htab, name, false, false);
   if (sh == NULL)
     return NULL;


More information about the Binutils-cvs mailing list