Bug 23953

Summary: gdb crashes when stepping into for loop where iterators are created and compared
Product: gdb Reporter: Bob Steagall <bob.steagall.cpp>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: bob.steagall.cpp, keiths, tromey
Priority: P2    
Version: 8.2   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Attachments: source file to demonstrate problem
Stack trace from corefile created by gdb segv
another stack trace, from gdb built '-g -O0'

Description Bob Steagall 2018-12-05 14:23:55 UTC
Created attachment 11431 [details]
source file to demonstrate problem

Consider the following code:

========================
#include <atomic>
#include <vector>

struct TS
{
    std::atomic<void*> mPtr;
};

int main()
{
    std::vector<TS> test(10);
    volatile int    i = 0;

    for (auto iter = test.begin();  iter != test.end();  ++iter)
    {
        ++i;
    }
    return 0;
}
========================

GDB 7.11 and 8.2 both crash when repeatedly stepping into the for loop on line 14 when compiled with gcc 8.2 and -std=c++17.

To reproduce:

$ g++ -std=c++17 -g -O0 test_dbg.cpp -o test_dbg
$ gdb test_dbg

inside of gdb:

(gdb) b 12
(gdb) r
(gdb) s
(gdb) s
(gdb) s
(gdb) s
(gdb) s
(gdb) s
 { gdb crashes with segv }


The following is a transcript from such a session:

Reading symbols from test_dbg...done.
(gdb) b 12
Breakpoint 1 at 0x400738: file test_dbg.cpp, line 12.
(gdb) r
Starting program: /space/tmp/test_dbg

Breakpoint 1, main () at test_dbg.cpp:12
(gdb) s
(gdb) s
std::vector<TS, std::allocator<TS> >::begin (this=0x7fffffffd7a0)
    at /usr/local/gcc/8.2.0/include/c++/8.2.0/bits/stl_vector.h:699
(gdb) s
__gnu_cxx::__normal_iterator<TS*, std::vector<TS, std::allocator<TS> > >::__normal_iterator (
    this=0x7fffffffd778, __i=@0x7fffffffd7a0: 0x614c20)
    at /usr/local/gcc/8.2.0/include/c++/8.2.0/bits/stl_iterator.h:781
(gdb) s
std::vector<TS, std::allocator<TS> >::end (this=0x7fffffffd7a0)
    at /usr/local/gcc/8.2.0/include/c++/8.2.0/bits/stl_vector.h:717
(gdb) s
__gnu_cxx::__normal_iterator<TS*, std::vector<TS, std::allocator<TS> > >::__normal_iterator (
    this=0x7fffffffd778, __i=@0x7fffffffd7a8: 0x614c70)
    at /usr/local/gcc/8.2.0/include/c++/8.2.0/bits/stl_iterator.h:781
(gdb) s
Segmentation fault (core dumped)

=============================
Here are the tool specs:

$ gdb -v
GNU gdb (GDB) 8.2
Copyright (C) 2018 Free Software Foundation, Inc. ...


$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/local/gcc/8.2.0/libexec/gcc/x86_64-kewb-linux-gnu/8.2.0/lto-wrapper
Target: x86_64-kewb-linux-gnu
Configured with: /space/zbuild/gcc-builder/gcc-8.2.0/configure -v --with-pkgversion='KEWB Computing Build' --prefix=/usr/local/gcc/8.2.0 --program-suffix= --enable-tls --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-languages=c,c++ --enable-lto --enable-bootstrap --disable-nls --disable-multilib --disable-install-libiberty --disable-werror --with-system-zlib
Thread model: posix
gcc version 8.2.0 (KEWB Computing Build) 


$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.5 LTS
Release:	16.04
Codename:	xenia

=============================
NOTES:

The problem appears to be related to the combination of std::atomic<T> as an element type AND the compilation flag -std=c++17.

If I change the flag to -std=c++14, gdb does not crash, and I can step thru the iterator instantiations and comparisons as expected.  Also, if I change the pointer type to void*, the crash does not occur, and stepping works correctly.  

I'm not sure if this is a GDB problem or a g++ codegen problem, so I'll be filing this report for both products.

Thanks,
--Bob
Comment 1 Tom Tromey 2018-12-05 18:12:26 UTC
I tried this on my Fedora 28 system, using git master gdb and:

pokyo. g++ --version
g++ (GCC) 8.2.1 20181011 (Red Hat 8.2.1-4)


... and I could not reproduce.  However, that doesn't necessarily
mean much since there are many possible variables.

Could you get a stack trace from gdb?  Maybe that would be helpful.
Or could you try git master gdb?  Perhaps the bug has already been
fixed.
Comment 2 Bob Steagall 2018-12-06 12:49:14 UTC
Created attachment 11432 [details]
Stack trace from corefile created by gdb segv

Per request by Tom Romey, I have attached a stack trace ("bt full") from the core file dropped by gdb when it SEGVs.
Comment 3 Bob Steagall 2018-12-06 13:23:52 UTC
Created attachment 11433 [details]
another stack trace, from gdb built '-g -O0'

I have rebuilt gdb from scratch with the following commands:

    $ CFLAGS='-g -O0' CXXFLAGS='-g -O0' ./configure
    $ make -j8

I then used this full-debug-info version of gdb to run the test program, using the same steps described in the ticket.  This gdb crashed in exactly the same way.

I then captured a stack from the resulting core file, which is attached here.  This may be more useful as variables are (mostly) not optimized out.

In both stack traces, the SEGV occurs at line 416 in the file value.c.  The pointer variable 'value' is NULL.


   │406     /* Returns true if VALUE is entirely covered by RANGES.  If the value                  │
   │407        is lazy, it'll be read now.  Note that RANGE is a pointer to                        │
   │408        pointer because reading the value might change *RANGE.  */                          │
   │409                                                                                            │
   │410     static int                                                                             │
   │411     value_entirely_covered_by_range_vector (struct value *value,                           │
   │412                         const std::vector<range> &ranges)                                  │
   │413     {                                                                                      │
   │414       /* We can only tell whether the whole value is optimized out /                       │
   │415          unavailable when we try to read it.  */                                           │
  >│416       if (value->lazy)                                                                     │
   │417         value_fetch_lazy (value);                                                          │
   │418                                                                                            │
Comment 4 Bob Steagall 2018-12-06 13:48:45 UTC
Working up the call stack, it looks like the call to value_static_field() on line 321 of file cp-valprint.c might be to blame, either returning NULL or throwing an exception such that the pointer "v" is never changed from its NULL initialization on line 317.

   │315               else if (field_is_static (&TYPE_FIELD (type, i)))                            │
   │316             {                                                                              │
   │317               struct value *v = NULL;                                                      │
   │318                                                                                            │
   │319               TRY                                                                          │
   │320                 {                                                                          │
   │321                   v = value_static_field (type, i);                                        │
   │322                 }                                                                          │
   │323                                                                                            │
   │324               CATCH (ex, RETURN_MASK_ERROR)                                                │
   │325                 {                                                                          │
   │326                   fprintf_filtered (stream,                                                │
   │327                         _("<error reading variable: %s>"),                                 │
   │328                         ex.message);                                                       │
   │329                 }                                                                          │
   │330               END_CATCH                                                                    │
   │331                                                                                            │
  >│332               cp_print_static_field (TYPE_FIELD_TYPE (type, i),                            │
   │333                          v, stream, recurse + 1,                                           │
   │334                          options);                                                         │
   │335             }                                                                              │
Comment 5 Bob Steagall 2018-12-06 13:55:15 UTC
The gdb binary, build against the 8.2 source code, and the core file are available for download here:

https://drive.google.com/open?id=1IDutIrUnJFYw6O9MxLRaiVxvX-WkRK2-
Comment 6 Keith Seitz 2018-12-06 16:17:17 UTC
Another 20020 dup. For unofficial workaround, see comment #1 in 20020.

*** This bug has been marked as a duplicate of bug 20020 ***