SIGSEGV on gdb 6.7*

Greg Law glaw@undo-software.com
Mon Feb 4 20:50:00 GMT 2008


Hi list,

I have been playing with gdb-6.7 and it appears there is a bug whereby 
reading registers can cause a SIGSEGV in gdb.  The simplest way I've 
found to cause the problem is to try to read a register after calling 
the flushregs maintenance command:

$ cat hello.c
#include <stdio.h>

int
main (void)
{
     printf ("hello, world\n");
     return 0;
}
$ gcc -g hello.c
$ ./gdb a.out
GNU gdb 6.7.1
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
<http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) start
Breakpoint 1 at 0x8048385: file hello.c, line 6.
Starting program: /mnt/duron/tests/a.out
main () at hello.c:6
6           printf ("Hello world\n");
(gdb) flushregs
Register cache flushed.
(gdb) print $pc
Segmentation fault (core dumped)
$


I realise that flushregs is not exactly a "supported" feature, but since 
the implementation of that command is simply:

static void
reg_flush_command (char *command, int from_tty)
{
   /* Force-flush the register cache.  */
   registers_changed ();
   if (from_tty)
     printf_filtered (_("Register cache flushed.\n"));
}

one wonders if there aren't other ways this issue can be triggered.

I have had a look around the code, and it's one of those "how could it 
ever have worked?" occasions (which of course typically means I've 
missed something important).  The implementation of registers_changed() 
is (essentially):

void
registers_changed (void)
{
   int i;

   regcache_xfree (current_regcache);
   current_regcache = NULL;

yet there appear to be pointers to the regcache squirrelled away in 
various other places, notably the prologue_cache member of the 
frame_info structure.

I'm sure I'm missing something here -- how come freeing current_regcache 
is safe with pointers to the register cache out-living it?

I have found that the following simple patch appears to fix (or at least 
work round) the SEGV triggered by flushregs:

Index: regcache.c
===================================================================
RCS file: /cvs/src/src/gdb/regcache.c,v
retrieving revision 1.163
diff -u -r1.163 regcache.c
--- regcache.c  1 Jan 2008 22:53:12 -0000       1.163
+++ regcache.c  3 Feb 2008 21:35:19 -0000
@@ -885,6 +885,7 @@
  {
    /* Force-flush the register cache.  */
    registers_changed ();
+  get_current_regcache ();
    if (from_tty)
      printf_filtered (_("Register cache flushed.\n"));
  }

However, I am insufficiently familiar with the gdb internals to know 
which, if any, of the other call-sites to register_changed() should be 
similarly updated.  Perhaps it would be safer simply to call 
get_current_regcache() from the end of registers_changed():

Index: regcache.c
===================================================================
RCS file: /cvs/src/src/gdb/regcache.c,v
retrieving revision 1.163
diff -u -r1.163 regcache.c
--- regcache.c  1 Jan 2008 22:53:12 -0000       1.163
+++ regcache.c  3 Feb 2008 21:49:37 -0000
@@ -472,6 +472,9 @@
    regcache_xfree (current_regcache);
    current_regcache = NULL;

+  /* Update the cache with the new registers. */
+  get_current_regcache ();
+
    /* Force cleanup of any alloca areas if using C alloca instead of
       a builtin alloca.  This particular call is used to clean up
       areas allocated by low level target code which may build up


I guess this might result in some "unnecessary" fetches of the register 
state, but that has to be favourable to a SEGV :)

Cheers,

Greg


-- 
Greg Law, Undo Software                       http://undo-software.com/



More information about the Gdb-patches mailing list