This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [OB PATCH] Frame static link: Handle null pointer.
- From: Joel Brobecker <brobecker at adacore dot com>
- To: Bernhard Heckel <bernhard dot heckel at intel dot com>
- Cc: gdb-patches at sourceware dot org
- Date: Tue, 7 Jun 2016 07:18:23 -0700
- Subject: Re: [OB PATCH] Frame static link: Handle null pointer.
- Authentication-results: sourceware.org; auth=none
- References: <1465299818-18697-1-git-send-email-bernhard dot heckel at intel dot com>
> 2016-06-07 Bernhard Heckel <bernhard.heckel@intel.com>
>
> gdb/Changelog:
> * findvar.c (follow_static_link): Check for valid pointer.
I was going to approve the patch, but then commit the version I had,
because the revision log describes in detail what happens. But
unfortunately for me, the patch has already been pushed. So I'll
post the revision log here.
| Subject: crash trying to print value of variable from up-level scope
|
| One of our users reported a crash trying to print the value of
| his variable. All we got to work with was an executable and
| a core file, representing the program's state where, trying
| to print the variable, causes the error.
|
| What we have been able to determine is that the variable is not
| defined in the currently selected frame. Instead, the currently
| selected frame corresponds to a subprogram which is nested inside
| another, where I expect the variable to be defined. As a result,
| GDB tries to find the frame where this variable is defined, and
| for this, calls findvar.c::follow_static_link.
|
| This function goes up the frame chain until it finds the frame
| whose frame base is equal to the value given to us by the static
| link. While doing so, it encounters a function whose corresponding
| symbol has a NULL SYMBOL_BLOCK_OPS, which leads to a SEGV when
| trying to dereference it to get the get_frame_base function:
|
| /* If we don't know how to compute FRAME's base address, don't give up:
| maybe the frame we are looking for is upper in the stace frame. */
| if (framefunc != NULL
| && SYMBOL_BLOCK_OPS (framefunc)->get_frame_base != NULL
| && (SYMBOL_BLOCK_OPS (framefunc)->get_frame_base (framefunc, frame)
| == upper_frame_base))
|
| Looking at the function's debugging info, I can see that it does
| not have a DW_AT_frame_base attribute, probably because it is
| inlined. As a result, dwarf2_symbol_mark_computed does not get
| called:
|
| /* If there is a location expression for DW_AT_frame_base, record
| it. */
| attr = dwarf2_attr (die, DW_AT_frame_base, cu);
| if (attr)
| dwarf2_symbol_mark_computed (attr, newobj->name, cu, 1);
|
| This means that the symbol we're building ends up keeping its default
| SYMBOL_ACLASS_INDEX (LOCK_BLOCK, see dwarf2read.c::new_symbol_full).
| This is the index that SYMBOL_BLOCK_OPS indirectly uses to get
| the associated block_ops:
|
| SYMBOL_BLOCK_OPS resolves to:
| -> SYMBOL_IMPL (symbol).ops_block, which resolves to:
| -> symbol_impls[(symbol)->aclass_index].ops_block
|
| And since aclass_index (SYMBOL_ACLASS_INDEX) is still LOCK_BLOCK,
| we're using the first elements few elements of the symbol_impls
| array, which are initialized as follow:
|
| /* Initialize elements of 'symbol_impl' for the constants in enum
| address_class. */
|
| static void
| initialize_ordinary_address_classes (void)
| {
| int i;
|
| for (i = 0; i < LOC_FINAL_VALUE; ++i)
| symbol_impl[i].aclass = (enum address_class) i;
| }
|
| This is why SYMBOL_BLOCK_OPS(framefunc) is NULL in our case.
|
| This patch fixes the issue, by adding a SYMBOL_BLOCK_OPS != NULL
| check.
|
| gdb/ChangeLog:
|
| * findvar.c (follow_static_link): Add SYMBOL_BLOCK_OPS != NULL
| check before trying to access its get_frame_base field.
|
| Tested on x86_64-linux with both the FSF and the AdaCore gdb testsuite.
| No test, unfortunately, because despite a few hours of efforts trying
| to play with inlined subroutines, I was unable to create a reproducer.
--
Joel