Menu

#2313 crash of the compiled program if typeid(int) is accessed

OTHER
closed
None
Support
fixed
Unknown
False
2017-02-01
2016-09-08
No

Compile the following program with g++ (GCC) 5.3.0
ld 2.25.1
When executed, it crashes

#include <iostream>
#include <typeinfo>

int main(int argc,char** argv){

  std::cout<<typeid(int).name()<<std::endl;

}

Discussion

  • WinPORTS

    WinPORTS - 2016-11-29

    Are you sure it crashes?
    It works fine on my environment.
    What is the expected output?

     
  • Fabio DallaLibera

    It does. You need to launch it from a dos prompt or the file browser. I just discovered that If you launch it from mingw terminal it works fine. The expected output is "i". The actual output (windows 7) is a dialog window:

    test.exe has stopped working

    Windows is collecting more information about the problem.
    This might take several minutes.

     

    Last edit: Fabio DallaLibera 2016-12-06
  • WinPORTS

    WinPORTS - 2016-12-08

    Are you sure? You seem confused (See attachment)
    It works fine from either 'prompt' window.

     
  • Fabio DallaLibera

    Here is a screenshot...

     
  • WinPORTS

    WinPORTS - 2016-12-08

    That screenshot doesn't help much, does it?

    Where do you think the problem lies and how it can be fixed?

     
  • Keith Marshall

    Keith Marshall - 2016-12-09
    • status: unread --> upstream
     
  • Keith Marshall

    Keith Marshall - 2016-12-09

    Guys, unless you are trying to illustrate a graphical effect, no screenshot is helpful, ever. Copy and paste your terminal output, with appropriate markup, directly into the report dialogue.

    Even less helpful, is any idiotic suggestion that because one of you is seeing a crash, and one is not, one of you must be confused. The only confusion I see here is a reference to a MinGW terminal, (since there is no meaningful definition for any such thing); perhaps you mean a distinction between running from an MSYS shell vs. a cmd.exe shell, (in whatever console container you happen to have chosen)? In any case, that should have no bearing on the issue.

    FWIW, I can consistently reproduce this issue: when cross-compiling the original test case with GCC-4.8.2, GCC-4.9.3, and GCC-5.3.0, and running in WinXP VM cmd.exe, or MSYS shell, or under Wine on the Linux host, it segfaults (apparently) when this method:

    /** Returns an @e implementation-defined byte string; this is not
     *  portable between compilers!  */
    const char* name() const _GLIBCXX_NOEXCEPT
    { return __name[0] == '*' ? __name + 1 : __name; }
    

    (defined within GCC's <typeinfo> header) attempts to dereference a NULL this pointer, (or just a NULL reference to the __name property itself). It also fails, when compiled natively by GCC-5.3.0 on the WinXP VM; it runs successfully, when cross-compiled by GCC-3.4.5.

    In any case, to be pragmatic, this appears to be a GCC implementation issue; you should raise it directly with the GCC maintainers, either via their mailing list, or GCC bugzilla.

     

    Last edit: Keith Marshall 2016-12-09
  • Keith Marshall

    Keith Marshall - 2016-12-09

    Some further information, from GCC-5.3.0 compile on WinXP VM:

    $ g++ -O0 -g foo.cc -o foo.exe
    $ gdb foo.exe
    .
    .
    (gdb) start
    Temporary breakpoint 2 at 0x401456: file foo.cc, line 6.
    Starting program: e:\foo.exe
    [New Thread 1616.0xb4]
    
    Temporary breakpoint 2, main (argc=1, argv=0x3d2470) at foo.cc:6
    6         std::cout<<typeid(int).name()<<std::endl;
    (gdb) stepi
    0x0040145b      6         std::cout<<typeid(int).name()<<std::endl;
    (gdb) disass
    Dump of assembler code for function main(int, char**):
       0x00401440 <+0>:     lea    0x4(%esp),%ecx
       0x00401444 <+4>:     and    $0xfffffff0,%esp
       0x00401447 <+7>:     pushl  -0x4(%ecx)
       0x0040144a <+10>:    push   %ebp
       0x0040144b <+11>:    mov    %esp,%ebp
       0x0040144d <+13>:    push   %ecx
       0x0040144e <+14>:    sub    $0x14,%esp
       0x00401451 <+17>:    call   0x401a10 <__main>
       0x00401456 <+22>:    mov    $0x0,%ecx
    => 0x0040145b <+4>:     call   0x408dd0 <std::type_info::name() const>
    .
    .
    

    Note that, immediately prior to the call to std::type_info::name() const, at 0x0040145b, GCC has emitted code to explicitly zero the ECX register. Single stepping into the method, and up to the point of the segfault at 0x00408ddc:

    (gdb) stepi
    0x00408ddc      100         { return __name[0] == '*' ? __name + 1 : __name; }
    (gdb)
    
    Program received signal SIGSEGV, Segmentation fault.
    0x00408ddc in std::type_info::name (this=0x0) at c:/mingw/lib/gcc/mingw32/5.3.0/include/c++/typeinfo:100
    100         { return __name[0] == '*' ? __name + 1 : __name; }
    (gdb) disass
    Dump of assembler code for function std::type_info::name() const:
       0x00408dd0 <+0>:     push   %ebp
       0x00408dd1 <+1>:     mov    %esp,%ebp
       0x00408dd3 <+3>:     sub    $0x4,%esp
       0x00408dd6 <+6>:     mov    %ecx,-0x4(%ebp)
       0x00408dd9 <+9>:     mov    -0x4(%ebp),%eax
    => 0x00408ddc <+12>:    mov    0x4(%eax),%eax
       0x00408ddf <+15>:    movzbl (%eax),%eax
       0x00408de2 <+18>:    cmp    $0x2a,%al
       0x00408de4 <+20>:    jne    0x408df1 <std::type_info::name() const+33>
       0x00408de6 <+22>:    mov    -0x4(%ebp),%eax
       0x00408de9 <+25>:    mov    0x4(%eax),%eax
       0x00408dec <+28>:    add    $0x1,%eax
       0x00408def <+31>:    jmp    0x408df7 <std::type_info::name() const+39>
       0x00408df1 <+33>:    mov    -0x4(%ebp),%eax
       0x00408df4 <+36>:    mov    0x4(%eax),%eax
       0x00408df7 <+39>:    leave
       0x00408df8 <+40>:    ret
    End of assembler dump.
    

    Note the indirect transfer of the zero from ECX to EAX, which is then dereferenced as a pointer, with a (likely too small) offset of only 4; this results in the segfault. At this point, the register contents are:

    (gdb) info reg
    eax            0x0      0
    ecx            0x0      0
    edx            0x77c61ae8       2009471720
    ebx            0x7ffdc000       2147336192
    esp            0x22ff44 0x22ff44
    ebp            0x22ff48 0x22ff48
    esi            0x7ffdec00       2147347456
    edi            0x160014 1441812
    eip            0x408ddc 0x408ddc <std::type_info::name() const+12>
    eflags         0x10306  [ PF TF IF RF ]
    cs             0x1b     27
    ss             0x23     35
    ds             0x23     35
    es             0x23     35
    fs             0x38     56
    gs             0x0      0
    
     
  • Keith Marshall

    Keith Marshall - 2016-12-09

    Interestingly, the test case runs just fine, if I compile using the static libstdc++, rather than the default dynamic version:

    $ g++ -O0 -g -static-libstdc++ foo.cc -o foo.exe
    $ ./foo
    i
    

    This is looking increasingly like a initialization bug, in the DLL variant of libstdc++. It may, apparently, be circumvented by linking with the static variant, but that may then introduce other problems, (e.g. with exception handling). You will still need to seek a resolution from the upstream maintainers of GCC, (specifically, those who maintain libstdc++).

     
  • Keith Marshall

    Keith Marshall - 2016-12-12
    • status: upstream --> open
    • assigned_to: Keith Marshall
     
  • Keith Marshall

    Keith Marshall - 2016-12-12

    In any case, to be pragmatic, this appears to be a GCC implementation issue; you should raise it directly with the GCC maintainers, either via their mailing list, or GCC bugzilla.

    Or maybe a binutils issue? Or a defect in my cross-compiler build environment? (The MinGW packages were created from a cross-native build). Or maybe something got stripped too zealously? (GCC's install-strip make goal is broken, so I stripped everything manually, after a regular install from the default -g -O2 build).

    Anyway, I rebuilt my cross-compiler tool chain, (including binutils-2.25.1 this time, instead of the binutils-2.26.20160125 I had installed previously), and recompiled the test case; it now runs fine under wine:

    $ rm *.dll
    $ ln mingw32-gcc-5.3.0/mingw32/lib/*.dll .
    $ mingw32-g++ -O3 -s foo.cc -o foo.exe
    $ ./foo.exe
    i
    

    I then proceeded to rebuild the cross-native tool chain, and installed that into a WinXP-VM, where once again, the test case now compiles and runs just fine:

    $ g++ -O3 -s foo.cc -o foo.exe
    $ ./foo
    i
    

    I'll get replacement packages uploaded to FRS, and listed in the mingw-get catalogue, just as soon as time permits.

     

    Last edit: Keith Marshall 2016-12-12
  • Fabio DallaLibera

    Thank you very much for your work!
    If it can help, I used only precompiled MinGW binaries downloaded from the official websites.
    And, If you run the exact same .exe from
    GNU bash, version 4.3.46(2)-release (i686-pc-msys)
    it prints "i" as expected, while if you run it by cmd.exe it crashes.

     

    Last edit: Fabio DallaLibera 2016-12-12
    • Keith Marshall

      Keith Marshall - 2016-12-12

      If you run the exact same .exe from GNU bash, version 4.3.46(2)-release (i686-pc-msys) it prints "i" as expected, while if you run it by cmd.exe it crashes.

      That makes absolutely no sense at all. My compilations of your test case, when run under GDB, show a NULL pointer dereference compiled directly into the (dynamically) linked image. This reference remains explicitly NULL, after all runtime relocations have been resolved, so must cause a segmentation fault irrespective of the shell under which you run it. That's exactly what I see: it crashes under both MSYS bash and cmd.exe.

      I don't know why the references, (in this case to the symbol _ZTIi in libstdc++-6.dll), were improperly resolved; after rebuilding the entire tool chain package set, from scratch, that reference is now correctly resolved, (for me). The rebuilt packages are now available in FRS, for direct download or installation/upgrade via mingw-get.

       
  • Keith Marshall

    Keith Marshall - 2017-02-01
    • status: open --> closed
    • Resolution: none --> fixed
     
  • Keith Marshall

    Keith Marshall - 2017-02-01

    In the absence of any further dialogue, I assume this has been resolved; closing accordingly.