public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4] [gdb/symtab] Fix an out of bounds array access in find_epilogue_using_linetable
@ 2024-04-08 12:57 Tom de Vries
  0 siblings, 0 replies; only message in thread
From: Tom de Vries @ 2024-04-08 12:57 UTC (permalink / raw)
  To: gdb-patches

From: Bernd Edlinger <bernd.edlinger@hotmail.de>

An out of bounds array access in find_epilogue_using_linetable causes random
test failures like these:

FAIL: gdb.base/unwind-on-each-insn-amd64.exp: foo: instruction 6: $fba_value == $fn_fba
FAIL: gdb.base/unwind-on-each-insn-amd64.exp: foo: instruction 6: check frame-id matches
FAIL: gdb.base/unwind-on-each-insn-amd64.exp: foo: instruction 6: bt 2
FAIL: gdb.base/unwind-on-each-insn-amd64.exp: foo: instruction 6: up
FAIL: gdb.base/unwind-on-each-insn-amd64.exp: foo: instruction 6: $sp_value == $::main_sp
FAIL: gdb.base/unwind-on-each-insn-amd64.exp: foo: instruction 6: $fba_value == $::main_fba
FAIL: gdb.base/unwind-on-each-insn-amd64.exp: foo: instruction 6: [string equal $fid $::main_fid]

Here the read happens below the first element of the line
table, and the test failure depends on the value that is
read from there.

It also happens that std::lower_bound returns a pointer exactly at the upper
bound of the line table, also here the read value is undefined, that happens
in this test:

FAIL: gdb.dwarf2/dw2-epilogue-begin.exp: confirm watchpoint doesn't trigger

Fixes: 528b729be1a2 ("gdb/dwarf2: Add support for DW_LNS_set_epilogue_begin in line-table")

Co-Authored-By: Tom de Vries <tdevries@suse.de>

PR symtab/31268
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31268
---
 gdb/symtab.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 77 insertions(+), 10 deletions(-)

diff --git a/gdb/symtab.c b/gdb/symtab.c
index 86603dfebc3..427d7b9f8b2 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4166,10 +4166,14 @@ find_epilogue_using_linetable (CORE_ADDR func_addr)
 	= unrelocated_addr (end_pc - objfile->text_section_offset ());
 
       const linetable *linetable = sal.symtab->linetable ();
-      /* This should find the last linetable entry of the current function.
-	 It is probably where the epilogue begins, but since the DWARF 5
-	 spec doesn't guarantee it, we iterate backwards through the function
-	 until we either find it or are sure that it doesn't exist.  */
+      if (linetable == nullptr || linetable->nitems == 0)
+	{
+	  /* Empty line table.  */
+	  return {};
+	}
+
+      /* Find the first linetable entry after the current function.  Note that
+	 this also may be an end_sequence entry.  */
       auto it = std::lower_bound
 	(linetable->item, linetable->item + linetable->nitems, unrel_end,
 	 [] (const linetable_entry &lte, unrelocated_addr pc)
@@ -4177,13 +4181,76 @@ find_epilogue_using_linetable (CORE_ADDR func_addr)
 	   return lte.unrelocated_pc () < pc;
 	 });
 
-      while (it->unrelocated_pc () >= unrel_start)
-      {
-	if (it->epilogue_begin)
-	  return {it->pc (objfile)};
-	it --;
-      }
+      if (it == linetable->item + linetable->nitems)
+	{
+	  /* We couldn't find either:
+	     - a linetable entry starting the function after the current
+	       function, or
+	     - an end_sequence entry that terminates the current function
+	       at unrel_end.
+	     This can happen when the linetable doesn't describe the full
+	     extent of the function, which shouldn't happen with
+	     compiler-generated debug info.  Handle the corner case
+	     conservatively.  */
+	  return {};
+	}
+      else
+	{
+	  if (unrel_end < it->unrelocated_pc ())
+	    {
+	      /* We found a line entry that starts past the end of the
+		 function.  This can happen if the previous entry straddles
+		 two functions, which shouldn't happen with compiler-generated
+		 debug info.  Handle the corner case conservatively.  */
+	      return {};
+	    }
+	  gdb_assert (unrel_end == it->unrelocated_pc ());
+	}
+
+      /* Move to the last linetable entry of the current function.  */
+      if (it == &linetable->item[0])
+	{
+	  /* Doing it-- would introduce undefined behaviour, avoid it by
+	     explicitly handling this case.  */
+	  return {};
+	}
+      it--;
+      if (it->unrelocated_pc () < unrel_start)
+	{
+	  /* Not in the current function.  */
+	  return {};
+	}
+      gdb_assert (it->unrelocated_pc () < unrel_end);
+
+      /* We're at the the last linetable entry of the current function.  This
+	 is probably where the epilogue begins, but since the DWARF 5 spec
+	 doesn't guarantee it, we iterate backwards through the current
+	 function until we either find the epilogue beginning, or are sure
+	 that it doesn't exist.  */
+      for (; it >= &linetable->item[0]; it--)
+	{
+	  if (it->unrelocated_pc () < unrel_start)
+	    {
+	      /* No longer in the current function.  */
+	      break;
+	    }
+
+	  if (it->epilogue_begin)
+	    {
+	      /* Found the beginning of the epilogue.  */
+	      return {it->pc (objfile)};
+	    }
+
+	  if (it == &linetable->item[0])
+	    {
+	      /* No more entries in the current function.
+		 Doing it-- would introduce undefined behaviour, avoid it by
+		 explicitly handling this case.  */
+	      break;
+	    }
+	}
     }
+
   return {};
 }
 

base-commit: 94a94c904da29bb733c19b5a0a168557c1819720
-- 
2.35.3


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-04-08 12:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-08 12:57 [PATCH v4] [gdb/symtab] Fix an out of bounds array access in find_epilogue_using_linetable Tom de Vries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).