Another segmentation fault in GDB 4.17 (and a patch for it)

Konrad Bernloehr bernlohr@ik3.fzk.de
Tue Jun 30 10:42:00 GMT 1998


Hello again,

Peter Schauer kindly provided a fix to the gdb segmentation fault 
which I reported recently (g77 compiled Fortran functions passing
character strings as CHARACTER*(*) arguments).
In fact, the second part of his patch isn't needed and the first part 
needs a little modification to avoid junk output. My suggested solution
(appended below) is to fix the length of these character strings to 1.
By default then, only the first character is displayed but the '@'
modifier to the print command can of course be used to show more.
The actual length of the character string is passed in an additional
variable '__g77_length_something' for a string named 'something'.

This variable caused another gdb segmentation fault with the same
example program:

      Program xyz
      Character c*30
      c = 'This is only a test'
      Call sub(c)
      End
      
      Subroutine sub ( c )
      Character c*(*)      
      Write(*,*) 'C=''',c,''''
      Write(*,*) 'LEN(C)=',Len(c)
      End

Example session:
   (gdb) break x.f:4
   Breakpoint 1 at 0x8048dcb: file x.f, line 4.
   (gdb) run
   Starting program: /home/users/bernlohr/x 

   Breakpoint 1, MAIN__ () at x.f:4
   4             Call sub(c)
   Current language:  auto; currently fortran
   (gdb) print c
   $1 = (84 'T', 104 'h', 105 'i', 115 's', 32 ' ', 105 'i', 115 's', 32 ' ', 111  'o', 110 'n', 108 'l', 121 'y', 32 ' ', 97 'a', 32 ' ', 116 't', 101 'e', 115 's', 116 't', 32 ' ', 32 ' ', 32 ' ', 32 ' ', 32 ' ', 32 ' ', 32 ' ', 32 ' ', 32 ' ', 32 ' ', 32 ' ')
   (gdb) step
   sub_ (c=0xbffff8c8, __g77_length_c=30) at x.f:9
   9             Write(*,*) 'C=''',c,''''
   (gdb) print c
   $2 = (PTR TO -> ( char (*))) 0xbffff8c8
   (gdb) print *c
   $3 = (<assumed size array> 84 'T')
   (gdb) whatis c
   type = PTR TO -> ( char (*))
   (gdb) whatis __g77_length_c   
   Segmentation fault

That's what gdb's core dump tells:
   GNU gdb 4.17
   Copyright 1998 Free Software Foundation, Inc.
   GDB is free software, covered by the GNU General Public License, and you are
   welcome to change it and/or distribute copies of it under certain conditions.
   Type "show copying" to see the conditions.
   There is absolutely no warranty for GDB.  Type "show warranty" for details.
   This GDB was configured as "i586-pc-linux-gnu"...
   Core was generated by `gdb/gdb /home/users/bernlohr/t'.
   Program terminated with signal 11, Segmentation fault.
   find_solib: Can't read pathname for load map: Input/output error

   #0  0x80ee366 in f_type_print_base (type=0x81c9d64, stream=0x819da68, show=-1, 
       level=0) at f-typeprint.c:414
   414           if (STREQ (TYPE_NAME (type), "char"))
   (gdb) where
   #0  0x80ee366 in f_type_print_base (type=0x81c9d64, stream=0x819da68, show=-1, 
       level=0) at f-typeprint.c:414
   #1  0x80edb7c in f_print_type (type=0x81c9d64, varstring=0x818626c "", 
       stream=0x819da68, show=-1, level=0) at f-typeprint.c:69
   #2  0x80eae00 in type_print (type=0x81c9d64, varstring=0x818626c "", 
       stream=0x819da68, show=-1) at typeprint.c:63
   #3  0x80eae90 in whatis_exp (exp=0x81b1ccf "__g77_length_c", show=-1)
       at typeprint.c:88
   #4  0x80eaece in whatis_command (exp=0x81b1ccf "__g77_length_c", from_tty=1)
       at typeprint.c:104
   #5  0x8100b23 in execute_command (p=0x81b1cdc "c", from_tty=1) at top.c:1259
   #6  0x8100d06 in command_loop () at top.c:1339
   #7  0x81099e5 in main (argc=2, argv=0xbffff910) at main.c:554

The fatal problem was that a NULL pointer was passed to the STREQ macro
which tries to optimize for speed and compares first the first character of
both strings. I modified the STREQ, STREQN, and STRCMP macros in gdb/defs.h
to catch such things in general (without too much tradeoff in speed, I hope).
Well, after that fix the 'whatis __g77_length_c' still shows a wrong type
(apparently due to incorrect debugging info from g77) but at least gdb
doesn't die anymore.

Once being at it, I noticed that g77 declares character strings as
arrays of characters in the debugging info. That is the reason why
the first 'print c' above results in such an ugly output. Therefore,
I decided that (at least for the present g77) characters of arrays
should instead be declared as character strings (TYPE_CODE_STRING
instead of TYPE_CODE_ARRAY). See the patch below.

With the final patched gdb the above gdb session again:
   (gdb) break x.f:4
   Breakpoint 1 at 0x8048dcb: file x.f, line 4.
   (gdb) run
   Starting program: /home/users/bernlohr/x 
   
   Breakpoint 1, MAIN__ () at x.f:4
   4             Call sub(c)
   Current language:  auto; currently fortran
   (gdb) print c
   $1 = 'This is only a test', ' ' <repeats 11 times>
   (gdb) step
   sub_ (c=0xbffff8b0, __g77_length_c=30) at x.f:9
   9             Write(*,*) 'C=''',c,''''
   (gdb) print c
   $2 = (PTR TO -> ( character*(*) )) 0xbffff8b0
   (gdb) print *c
   $3 = 'T'
   (gdb) whatis c
   type = PTR TO -> ( character*(*) )
   (gdb) whatis __g77_length_c
   type = character
   (gdb) print __g77_length_c
   $4 = 30
   (gdb) print *c@30
   $5 = ('T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'o', 'n', 'l', 'y', ' ', 'a', ' ', 't', 'e', 's', 't', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ')

By the way, I would also like to 'print' a substring as a Fortran expression, e.g.
'print C(5:20)', but I can only 'print *(c+4)@16'. I will leave that as an
exercise.

     Kind regards,
      Konrad Bernloehr

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       Dr. Konrad Bernloehr,  Institut fuer Kernphysik III
     Forschungszentrum Karlsruhe,  76021 Karlsruhe,  Germany
                   E-mail: bernlohr@ik3.fzk.de


*** gdb/gdbtypes.c.orig     Mon Jun 29 12:05:04 1998
--- gdb/gdbtypes.c  Tue Jun 30 18:10:17 1998
***************
*** 31,36 ****
--- 31,37 ----
  #include "value.h"
  #include "demangle.h"
  #include "complaints.h"
+ #include "buildsym.h"
  
  /* These variables point to the objects
     representing the predefined C data types.  */
***************
*** 436,447 ****
--- 437,465 ----
        result_type = alloc_type (TYPE_OBJFILE (range_type));
      }
    TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
+   /* Fortran character strings were told by g77 to be character arrays */
+   /* which can be fixed here. */
+   if ( TYPE_NAME(element_type) != NULL && 
+        current_subfile->language == language_fortran )
+      if ( STRCMP(TYPE_NAME(element_type),"char") == 0 )
+         TYPE_CODE (result_type) = TYPE_CODE_STRING;
    TYPE_TARGET_TYPE (result_type) = element_type;
    if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
      low_bound = high_bound = 0;
    CHECK_TYPEDEF (element_type);
    TYPE_LENGTH (result_type) =
      TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
+ 
+   /* Fix to avoid segmentation faults when printing for example */
+   /* Fortran variables passed as CHARACTER*(*). */
+   if (low_bound > high_bound)
+     {
+       /* A minimum length of 1 is needed to avoid chunk output */
+       TYPE_LENGTH (result_type) = 1;
+       if (high_bound == -1)
+         TYPE_ARRAY_UPPER_BOUND_TYPE(result_type) = BOUND_CANNOT_BE_DETERMINED;
+     }  
+ 
    TYPE_NFIELDS (result_type) = 1;
    TYPE_FIELDS (result_type) =
      (struct field *) TYPE_ALLOC (result_type, sizeof (struct field));
*** gdb/defs.h.orig Tue Jun 30 13:16:27 1998
--- gdb/defs.h      Tue Jun 30 13:16:27 1998
***************
*** 77,85 ****
  /* Gdb does *lots* of string compares.  Use macros to speed them up by
     avoiding function calls if the first characters are not the same. */
  
! #define STRCMP(a,b) (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b))
! #define STREQ(a,b) (*(a) == *(b) ? !strcmp ((a), (b)) : 0)
! #define STREQN(a,b,c) (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0)
  
  /* The character GNU C++ uses to build identifiers that must be unique from
     the program's identifiers (such as $this and $$vptr).  */
--- 77,85 ----
  /* Gdb does *lots* of string compares.  Use macros to speed them up by
     avoiding function calls if the first characters are not the same. */
  
! #define STRCMP(a,b) ((a)!=NULL && (b)!=NULL ? (*(a) == *(b) ? strcmp ((a), (b)) : (int)*(a) - (int)*(b)) : 999)
! #define STREQ(a,b) ((a)!=NULL && (b)!=NULL ? (*(a) == *(b) ? !strcmp ((a), (b)) : 0) : 999)
! #define STREQN(a,b,c) ((a)!=NULL && (b)!=NULL ? (*(a) == *(b) ? !strncmp ((a), (b), (c)) : 0) : 999)
  
  /* The character GNU C++ uses to build identifiers that must be unique from
     the program's identifiers (such as $this and $$vptr).  */



More information about the Gdb mailing list