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

Peter.Schauer Peter.Schauer@regent.e-technik.tu-muenchen.de
Wed Jul 1 02:39:00 GMT 1998


Sorry, I do not intend to spend time on any F77 support fixes, as I am lacking
the required Fortran expertise.
I have a few objections to the proposed patches however:

> 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.

This might work for Fortran, but it will break C and C++, where
dynamic arrays are represented with a type length of zero.
Perhaps the proper fix is to remove the arbitrary output of one element
for Fortran assumed size arrays in f-valprint.c, which will get rid of
the junk output when printing an assumed size array.

> 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).

These macros are used in inner loops, so I think that we should not
do the extra test, and the calling code in f-typeprint.c should get fixed.
Perhaps g77 should output the type of __g77_length_* as `integer*4', to
avoid an `Invalid type code' message from GDB, but I don't know.

> +   /* 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;

If we really want to do this, then it should be done in the symbol reader.
A cleaner solution might be to handle character arrays explicitly
in f-valprint.c:f77_print_array_1.

> 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).  */
> 
> 

-- 
Peter Schauer			pes@regent.e-technik.tu-muenchen.de



More information about the Gdb mailing list