This is the mail archive of the gdb-prs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug backtrace/15558] "set backtrace limit" can cause assertion failure


https://sourceware.org/bugzilla/show_bug.cgi?id=15558

--- Comment #2 from cvs-commit at gcc dot gnu.org <cvs-commit at gcc dot gnu.org> ---
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gdb and binutils".

The branch, master has been updated
       via  51d481464ec03be1f5479ed648cc38fb944d7fc0 (commit)
      from  1bdad2e0421a56e16c0f4623e6320e1225cbe5ee (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=51d481464ec03be1f5479ed648cc38fb944d7fc0

commit 51d481464ec03be1f5479ed648cc38fb944d7fc0
Author: Pedro Alves <palves@redhat.com>
Date:   Fri Apr 18 10:15:21 2014 +0100

    Fix PR backtrace/15558

    This PR is about an assertion failure in GDB that can be triggered by
    setting "backtrace limit" to a value that causes GDB to stop unwinding
    after an inline frame.  In this case, an assertion in
    inline_frame_this_id will trigger:

      /* We need a valid frame ID, so we need to be based on a valid
         frame.  (...).  */
      gdb_assert (frame_id_p (*this_id));

    Looking at the function:

     static void
     inline_frame_this_id (struct frame_info *this_frame,
                   void **this_cache,
                   struct frame_id *this_id)
     {
       struct symbol *func;

       /* In order to have a stable frame ID for a given inline function,
          we must get the stack / special addresses from the underlying
          real frame's this_id method.  So we must call get_prev_frame.
          Because we are inlined into some function, there must be previous
          frames, so this is safe - as long as we're careful not to
          create any cycles.  */
       *this_id = get_frame_id (get_prev_frame (this_frame));

    we see we're computing the frame id for the inline frame.  If this is
    an inline frame, which is a virtual frame constructed based on debug
    info, on top of a real stack frame, we should _always_ be able to find
    where the frame was inlined into, as that ultimately just means
    peeling off the virtual frames on top of the real stack frame.  If
    there ultimately was no prev (real) stack frame, then we wouldn't have
    been able to construct the inline frame either, by design.  That's
    what the assertion catches.

    So we have an inline frame, we should _always_ be able to compute its
    ID, even if that means bypassing the user backtrace limits to get at
    the real stack frame's info.  The problem is that inline_frame_id
    calls get_prev_frame, and that takes user backtrace limits into
    account.  Code that wants to bypass the limits calls get_prev_frame_1
    instead.

    Note how get_prev_frame_1 already skips all checks for inline frames:

       /* If we are unwinding from an inline frame, all of the below tests
          were already performed when we unwound from the next non-inline
          frame.  We must skip them, since we can not get THIS_FRAME's ID
          until we have unwound all the way down to the previous non-inline
          frame.  */
       if (get_frame_type (this_frame) == INLINE_FRAME)
         return get_prev_frame_if_no_cycle (this_frame);

    And note how the related frame_unwind_caller_id function also uses
    get_prev_frame_1:

     struct frame_id
     frame_unwind_caller_id (struct frame_info *next_frame)
     {
       struct frame_info *this_frame;

       /* Use get_prev_frame_1, and not get_prev_frame.  The latter will
truncate
          the frame chain, leading to this function unintentionally
          returning a null_frame_id (e.g., when a caller requests the frame
          ID of "main()"s caller.  */

       next_frame = skip_artificial_frames (next_frame);
       this_frame = get_prev_frame_1 (next_frame);
       if (this_frame)
         return get_frame_id (skip_artificial_frames (this_frame));
       else
         return null_frame_id;
     }

    get_prev_frame_1 is currently static in frame.c.  As a _1 suffix is
    not a good name for an extern function, I've renamed it.

    Tested on x86-64 Fedora 17.

    gdb/
    2014-04-18  Pedro alves  <palves@redhat.com>
            Tom Tromey  <tromey@redhat.com>

        PR backtrace/15558
        * frame.c (get_prev_frame_1): Rename to ...
        (get_prev_frame_always): ... this, and make extern.  Adjust.
        (skip_artificial_frames): Use get_prev_frame_always.
        (frame_unwind_caller_id, frame_pop, get_prev_frame)
        (get_frame_unwind_stop_reason): Adjust to rename.
        * frame.h (get_prev_frame_always): Declare.
        * inline-frame.c: Include frame.h.
        (inline_frame_this_id): Use get_prev_frame_always.

    gdb/testsuite/
    2014-04-18  Tom Tromey  <palves@redhat.com>
            Pedro alves  <tromey@redhat.com>

        PR backtrace/15558
        * gdb.opt/inline-bt.exp: Test backtracing from an inline function
        with a backtrace limit.
        * gdb.python/py-frame-inline.exp: Test running to an inline
        function with a backtrace limit, and printing the newest frame.
        * gdb.python/py-frame-inline.c (main): Call f.

-----------------------------------------------------------------------

Summary of changes:
 gdb/ChangeLog                                |   13 +++++++++++
 gdb/frame.c                                  |   31 +++++++++++++++-----------
 gdb/frame.h                                  |    7 ++++++
 gdb/inline-frame.c                           |   11 +++++----
 gdb/testsuite/ChangeLog                      |   10 ++++++++
 gdb/testsuite/gdb.opt/inline-bt.exp          |   16 +++++++++++++
 gdb/testsuite/gdb.python/py-frame-inline.c   |    4 ++-
 gdb/testsuite/gdb.python/py-frame-inline.exp |   14 +++++++++++
 8 files changed, 87 insertions(+), 19 deletions(-)

-- 
You are receiving this mail because:
You are on the CC list for the bug.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]