Bug 15468 - crash breakpoint.c:5940: internal-error: print_one_breakpoint_location
Summary: crash breakpoint.c:5940: internal-error: print_one_breakpoint_location
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: c++ (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 9.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 15679 24519 (view as bug list)
Depends on:
Blocks:
 
Reported: 2013-05-15 08:36 UTC by Heggman
Modified: 2019-07-09 20:18 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Heggman 2013-05-15 08:36:02 UTC
I use gdb in emacs (24.3, trunk) with GUD.

Then I set a execption point through "catch throw". This works. Also, all is good if execption point is reached.

But as soon as  I try to print the catch point -> crash.

When using M-x gud-gdb (with gdb --fullname) there is no automatic display of breakpoints. So crash occurs if I try to print the breakpoints excplictely.

When using M-x gdb version of GUD with "gdb -i=mi ..." and have all frames displayed (threads, breakpoints, watches, ...) crash occurs directly after executing "catch throw".

Please see transcript below:

GNU gdb (GDB) 7.6
Copyright (C) 2013 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 "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Loaded STL pretty printers
Loading ~/.gdb/pythonPegaPlan.py
Loaded ~/.gdb/pythonPegaPlan.py
Reading symbols from /users/q4de3tsy926/user3/heierma1/sniff/6.4/appl/fscp/fscp_gui/linux-gnu/fscp.exe...done.
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) r
Starting program: /users/q4de3tsy926/user3/heierma1/sniff/6.4/appl/fscp/fscp_gui/linux-gnu/fscp.exe 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/tls/libthread_db.so.1".

*** starting module PP FsCp (PP 6.4.3) linked on May 15 2013 at 02:14:19 on linux-gnu

*** fscp.exe: initializing ...
[New Thread 0x40200960 (LWP 21881)]
[New Thread 0x40401960 (LWP 21882)]
[New Thread 0x40602960 (LWP 21883)]
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x89ad470, tinfo=0x2920e60 <typeinfo for EShapefileError>, 
    dest=0x17f1fdc <EShapefileError::~EShapefileError()>) at /users/dxcoty/user1/markus/MAKE/gcc-4.1.2/libstdc++-v3/libsupc++/eh_throw.cc:64
64	/users/dxcutz/user1/heiner/MAKE/gcc-4.1.2/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory.
(gdb)  i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   
breakpoint.c:5940: internal-error: print_one_breakpoint_location: Assertion `b->loc == NULL || b->loc->next == NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) y
breakpoint.c:5940: internal-error: print_one_breakpoint_location: Assertion `b->loc == NULL || b->loc->next == NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Unable to dump core, use `ulimit -c unlimited' before executing GDB next time.
Debugger exited abnormally with code 1

FYI: The bug is also referenced in the IMHO unrelated kde(velop) bug tracking system: https://bugs.kde.org/show_bug.cgi?id=316656
Comment 1 Tom Tromey 2013-05-15 17:25:45 UTC
I was able to reproduce this by creating a program that
had two functions named __cxa_throw.
Comment 2 Heggman 2013-05-16 11:48:11 UTC
Can you please tell me how to check that for my executable?
Comment 3 Tom Tromey 2013-05-16 14:14:01 UTC
You could try "info func __cxa_throw" in gdb and see if it
gives more than one answer.
Or, "nm" may tell you, but you'd have to examine each .so as well.
Comment 4 Heggman 2013-05-18 00:17:10 UTC
Confirmed. There are two references to __cxa_throw.

So as a workaround I use "break __cxa_throw" instead of "catch throw", then gdb can handle the two incarnations of this function.

Nevertheless older versions of gdb -- I checked at least 6.8, 7.2 and 7.3.1 -- can handle this without problems.
Comment 5 Spencer Baugh 2017-01-03 21:32:28 UTC
This can also be triggered through normal usage of multiple inferior debugging.

With any typical C++ program (such as hello.cc at the end of this comment) the following sequence of commands...

(gdb) catch throw                                                                                                                                    
(gdb) add-inferior -copies 2 -exec hello                                                                                                             
(gdb) infe 2                                                                                                                                         
(gdb) break main                                                                                                                                     
(gdb) run                                                                                                                                            
(gdb) infe 3                                                                                                                                         
(gdb) run                                                                                                                                            
(gdb) info break                                                                                                                                     

...will trigger this error:
breakpoint.c:6384: internal-error: print_one_breakpoint_location: Assertion `b->loc == NULL || b->loc->next == NULL' failed.
 
It's key that the catchpoint is set before the inferiors are created. Whenever the catchpoint is pending before multiple C++ inferiors come into existence, this error will happen. 

hello.cc:
#include <iostream>
int main() { std::cout << "Hello World!" << std::endl; }
Comment 6 MasterAlfred 2019-04-07 15:41:17 UTC
Can't this be changed to a warning?

Using GDB from IDEs (Eclipse CDT) this will break debugging completely when using auto-solib-add on for some projects. 
It seems like this issue has been around at since 2012.

I built GDB myself removing the assert, but it would be nice to have a workaround/fix upstream.
Comment 7 Tom Tromey 2019-07-09 14:04:22 UTC
*** Bug 15679 has been marked as a duplicate of this bug. ***
Comment 8 Tom Tromey 2019-07-09 14:04:26 UTC
*** Bug 24519 has been marked as a duplicate of this bug. ***
Comment 9 Sourceware Commits 2019-07-09 19:01:25 UTC
The master branch has been updated by Pedro Alves <palves@sourceware.org>:

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

commit b58a68fe5709ed205c3ac54065f1783ce58d9a01
Author: Pedro Alves <palves@redhat.com>
Date:   Tue Jul 9 19:26:15 2019 +0100

    Fix "info break" + "catch catch" + -static-{libstdc++,libgcc}
    
    If you debug current GDB, set a "catch catch/throw/rethrow"
    catchpoint, and then do "info breakpoints", the top GDB hits an
    internal error:
    
     (top-gdb) catch catch
     Catchpoint 1 (catch)
     (top-gdb) info breakpoints
     Num     Type           Disp Enb Address            What
     1       breakpoint     keep y   src/gdb/breakpoint.c:6040: internal-error: void print_one_breakpoint_location(breakpoint*, bp_location*, int, bp_location**, int): Assertion `b->loc == NULL || b->loc->next == NULL' failed.
     A problem internal to GDB has been detected,
     further debugging may prove unreliable.
     Quit this debugging session? (y or n)
    
    The assertion in question is asserting that a breakpoint with a
    print_one method only has one location, and it fails because this
    catchpoint ends up with two locations.
    
    Internally, "catch catch" sets a breakpoint at __cxa_begin_catch.  If
    we do that manually, we see the locations:
    
      (top-gdb) b -qualified __cxa_begin_catch
      Breakpoint 2 at 0xb122b0 (2 locations)
      (top-gdb) info breakpoints
      Num     Type           Disp Enb Address            What
      2       breakpoint     keep y   <MULTIPLE>
      2.1                         y   0x0000000000b122b0 <__cxa_begin_catch>
      2.2                         y   0x00007ffff2f4ddb0 in __cxxabiv1::__cxa_begin_catch(void*) at ../../../../libstdc++-v3/libsupc++/eh_catch.cc:41
    
    Note that I had used -qualified.  It seems strange that we get a
    location for a namespaced symbol, but that happens because the minimal
    symbol for that address is indeed called __cxa_begin_catch.
    
    The real issue is that gdb is linked with
    -static-libgcc/-static-libstdc++.  And then, it _also_ ends up with
    shared libstc++ loaded:
    
      (top-gdb) info sharedlibrary stdc++
      From                To                  Syms Read   Shared Object Library
      0x00007ffff2f4b380  0x00007ffff2ffc018  Yes         /lib64/libstdc++.so.6
    
    Location 2.2 is set within libstdc++.so.6's range:
    
      (top-gdb) p 0x00007ffff2f4b380 <= 0x00007ffff2f4ddb0 && 0x00007ffff2f4ddb0 < 0x00007ffff2ffc018
      $1 = true
    
    So due to -static-lib*, we end up with _two_ copies of the
    __cxa_begin_catch code:
    
      (top-gdb) disassemble 0x0000000000b122b0
      Dump of assembler code for function __cxa_begin_catch:
         0x0000000000b122b0 <+0>:     push   %rbx
         0x0000000000b122b1 <+1>:     mov    %rdi,%rbx
         0x0000000000b122b4 <+4>:     callq  0xb11a80 <__cxa_get_globals>
         0x0000000000b122b9 <+9>:     movabs $0xb8b1aabcbcd4d500,%rdx
      ...
    
      (top-gdb) disassemble 0x00007ffff2f4ddb0
      Dump of assembler code for function __cxxabiv1::__cxa_begin_catch(void*):
         0x00007ffff2f4ddb0 <+0>:     push   %rbx
         0x00007ffff2f4ddb1 <+1>:     mov    %rdi,%rbx
         0x00007ffff2f4ddb4 <+4>:     callq  0x7ffff2f4a090 <__cxa_get_globals@plt>
         0x00007ffff2f4ddb9 <+9>:     movabs $0xb8b1aabcbcd4d500,%rdx
      ...
    
    I think we end up with libstdc++.so.6 loaded because
    libsource-highlight.so depends on it.
    
    Irrespective of whether it's a good idea to use
    -static-libgcc/-static-libstdc++, GDB should not crash.  Since there
    are two copies of the code, it seems right to have more than one
    location.  So the fix is just to remove the assertion.
    
    A testcase is included, which mimics the scenerio described above,
    with binary linked with -static-lib{stdc++,gcc} and a shared library
    that is linked normally, along with other combinations for good
    measure.
    
    gdb/ChangeLog:
    2019-07-09  Pedro Alves  <palves@redhat.com>
    
    	PR c++/15468
    	* breakpoint.c (print_one_breakpoint_location): Remove
    	single-location assert.
    
    gdb/testsuite/ChangeLog:
    2019-07-09  Pedro Alves  <palves@redhat.com>
    
    	PR c++/15468
    	* gdb.cp/except-multi-location-lib.cc: New.
    	* gdb.cp/except-multi-location-main.cc: New.
    	* gdb.cp/except-multi-location.exp: New.
Comment 10 Tom Tromey 2019-07-09 20:18:53 UTC
Fixed.