Menu

#893 thread_local variable crashes std::thread when run under gdb

v1.0 (example)
open
nobody
None
5
2021-04-28
2021-04-27
No

Consider the following code:

#include <sstream>
#include <thread>

int main() {
  std::thread([&]() {
    thread_local std::ostringstream oss;
    static_cast<void>(oss);  // Make sure 'oss' is initialized.
  }).join();
}

I've tried the following scenario with two downstream compilers/debuggers:

  1. Compile the code with g++ test.cpp -o test.exe -ggdb (the last key is optional).
  2. Run test.exe successfully.
  3. Run it under gdb with gdb -ex run -ex where -ex "set confirm off" -ex q test.exe (same as running gdb test.exe and typing run, where, q and confirming)

Expected output: code runs and terminates successfully.
Actual result: code crashes somewhere around second thread termination.

I've tested it both with ancient g++.EXE (tdm-1) 4.9.2/gdb GNU gdb (GDB) 7.6.1 from TDM-GCC (it required additional -std=c++11), and with a very recent msys2 build: g++ (Rev10, Built by MSYS2 project) 10.2.0/GNU gdb (GDB) 10.1. The latter's output is as follows:

GNU gdb (GDB) 10.1
Copyright (C) 2020 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-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test.exe...
Starting program: F:\_0_MAIN\Teach\2020\cpp\drafts\210427\test.exe 
warning: [doctest] doctest version is "2.4.6"
[doctest] run with "--help" for options
[New Thread 11556.0xb0]
warning: Critical error detected c0000374

Thread 2 received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 11556.0xb0]
0x00000000774cf680 in ntdll!RtlUnhandledExceptionFilter ()
   from C:\Windows\SYSTEM32\ntdll.dll
#0  0x00000000774cf680 in ntdll!RtlUnhandledExceptionFilter ()
   from C:\Windows\SYSTEM32\ntdll.dll
#1  0x00000000774cfc86 in ntdll!EtwEnumerateProcessRegGuids ()
   from C:\Windows\SYSTEM32\ntdll.dll
#2  0x00000000774d08a2 in ntdll!RtlQueryProcessLockInformation ()
   from C:\Windows\SYSTEM32\ntdll.dll
#3  0x00000000774d29b4 in ntdll!RtlLogStackBackTrace ()
   from C:\Windows\SYSTEM32\ntdll.dll
#4  0x000000007743a0b0 in ntdll!RtlFreeHeap ()
   from C:\Windows\SYSTEM32\ntdll.dll
#5  0x000007feff0310c8 in msvcrt!free () from C:\Windows\system32\msvcrt.dll
#6  0x000007feccd19827 in ?? ()
   from C:\Software\msys64\mingw64\bin\libstdc++-6.dll
#7  0x000000013f9599a6 in run_dtor_list (ptr=<synthetic pointer>)
    at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/tls_atexit.c:59
#8  tls_callback (hDllHandle=<optimized out>, dwReason=<optimized out>, 
    lpReserved=<optimized out>)
    at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/tls_atexit.c:155
#9  0x0000000077455088 in ntdll!RtlpUnWaitCriticalSection ()
   from C:\Windows\SYSTEM32\ntdll.dll
#10 0x000000007744868f in ntdll!LdrShutdownThread ()
   from C:\Windows\SYSTEM32\ntdll.dll
#11 0x0000000077453ee8 in ntdll!RtlExitUserThread ()
   from C:\Windows\SYSTEM32\ntdll.dll
#12 0x000007feff034213 in msvcrt!_endthreadex ()
   from C:\Windows\system32\msvcrt.dll
#13 0x000007fef1394f6e in ?? ()
   from C:\Software\msys64\mingw64\bin\libwinpthread-1.dll
#14 0x000007feff03415f in srand () from C:\Windows\system32\msvcrt.dll
#15 0x000007feff036ebd in msvcrt!_ftime64_s ()
   from C:\Windows\system32\msvcrt.dll
#16 0x00000000772059cd in KERNEL32!BaseThreadInitThunk ()
   from C:\Windows\system32\kernel32.dll
#17 0x000000007746383d in ntdll!RtlUserThreadStart ()
   from C:\Windows\SYSTEM32\ntdll.dll
#18 0x0000000000000000 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

the former's output is as follows:

GNU gdb (GDB) 7.6.1
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 "mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from D:\home\yeputons\210427\test.exe...done.
Starting program: D:\home\yeputons\210427/test.exe 
[New Thread 10004.0x1518]
[New Thread 10004.0x1f78]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 10004.0x1f78]
0x00470deb in std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_ostringstream() ()
#0  0x00470deb in std::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_ostringstream() ()
#1  0x00000001 in ?? ()
#2  0x00000000 in ?? ()

The first issue where I encountered this problem is https://github.com/onqtam/doctest/issues/501

Discussion

  • Egor Suvorov

    Egor Suvorov - 2021-04-27

    P.S. Sorry, I've accidentally attached wrong stacktraces for gdb 10/gdb 10, here is a correct one:

    GNU gdb (GDB) 10.1
    Copyright (C) 2020 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-w64-mingw32".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <https://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
        <http://www.gnu.org/software/gdb/documentation/>.
    
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from test.exe...
    Starting program: F:\_0_MAIN\Teach\2020\cpp\drafts\210427\report\test.exe 
    [New Thread 11344.0x19a4]
    warning: Critical error detected c0000374
    
    Thread 2 received signal SIGTRAP, Trace/breakpoint trap.
    [Switching to Thread 11344.0x19a4]
    0x00000000774cf680 in ntdll!RtlUnhandledExceptionFilter ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #0  0x00000000774cf680 in ntdll!RtlUnhandledExceptionFilter ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #1  0x00000000774cfc86 in ntdll!EtwEnumerateProcessRegGuids ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #2  0x00000000774d08a2 in ntdll!RtlQueryProcessLockInformation ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #3  0x00000000774d29b4 in ntdll!RtlLogStackBackTrace ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #4  0x000000007743a0b0 in ntdll!RtlFreeHeap ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #5  0x000007feff0310c8 in msvcrt!free () from C:\Windows\system32\msvcrt.dll
    #6  0x000007fecca29827 in ?? ()
       from C:\Software\msys64\mingw64\bin\libstdc++-6.dll
    #7  0x000000013f7f2706 in run_dtor_list (ptr=<synthetic pointer>)
        at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/tls_atexit.c:59
    #8  tls_callback (hDllHandle=<optimized out>, dwReason=<optimized out>, 
        lpReserved=<optimized out>)
        at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/tls_atexit.c:155
    #9  0x0000000077455088 in ntdll!RtlpUnWaitCriticalSection ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #10 0x000000007744868f in ntdll!LdrShutdownThread ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #11 0x0000000077453ee8 in ntdll!RtlExitUserThread ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #12 0x000007feff034213 in msvcrt!_endthreadex ()
       from C:\Windows\system32\msvcrt.dll
    #13 0x000007fef1394f6e in ?? ()
       from C:\Software\msys64\mingw64\bin\libwinpthread-1.dll
    #14 0x000007feff03415f in srand () from C:\Windows\system32\msvcrt.dll
    #15 0x000007feff036ebd in msvcrt!_ftime64_s ()
       from C:\Windows\system32\msvcrt.dll
    #16 0x00000000772059cd in KERNEL32!BaseThreadInitThunk ()
       from C:\Windows\system32\kernel32.dll
    #17 0x000000007746383d in ntdll!RtlUserThreadStart ()
       from C:\Windows\SYSTEM32\ntdll.dll
    #18 0x0000000000000000 in ?? ()
    Backtrace stopped: previous frame inner to this frame (corrupt stack?)
    
     
  • Egor Suvorov

    Egor Suvorov - 2021-04-27

    Another datapoint: compiled on Ubuntu 20.04 with g++-mingw-w64-x86-64 9.3.0-7ubuntu1+22~exp1ubuntu4 (x86_64-w64-mingw32-g++-posix with -static and -static-libgcc specifically, -win32 version does not support std::thread apparently) , ran on Windows, it crashed on thread termination even without gdb attached.

     
  • Egor Suvorov

    Egor Suvorov - 2021-04-28

    A simpler example (testing with msys2's gcc 10.2.0/gdb 10.1):

    #include <cstdio>
    #include <thread>
    
    struct S {
        long long x;
        S() : x(0x1234) {
            printf("S(): this=%p, x=0x%llX\n", this, x);
        }
        S(const S &) = delete;
        ~S() {
            printf("~S(): this=%p, x=0x%llX\n", this, x);
        }
    };
    
    int main() {
      std::thread([&]() {
        thread_local S oss;
        static_cast<void>(oss);  // Make sure 'oss' is initialized.
      }).join();
    }
    

    Here x in constructor is 0x1234 as expected, but it becomes 0xFEEEFEEEFEEEFEEE before destructor is called, see attached gdb-session-1.txt

    I was able to google up a very similar issue from 2017: https://github.com/msys2/MINGW-packages/issues/2519

     

Log in to post a comment.

MongoDB Logo MongoDB