From: curt <mi...@no...> - 2013-12-30 01:42:09
|
Just ported some libraries of mine to a new project and one of the well-used one choked and died. After some sluthing I found the problem appears to be thing mingw linker getting confused on what to call. Simplified example: #include <stdio.h> #include <stdarg.h> void polyCrash( const char* format, ... ) { va_list arg; va_start( arg, format ); char buf[80]; vsnprintf( buf, 80, format, arg ); va_end( arg ); } void polyCrash( const char* format, va_list arg ) { char buf[80]; vsnprintf( buf, 80, format, arg ); } int main( int argc,char *argv[] ) { polyCrash( "%s", (char *)"crash" } compile with a simple: gcc -o t test.cpp and boom crash, dump looks like this: cygwin$ gcc src/main.cpp -O0 -ggdb -o test cygwin$ gdb test 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 C:\curt\dot\fl\world\test.exe...done. (gdb) run Starting program: C:\curt\dot\fl\world/test.exe [New Thread 5564.0x668] Program received signal SIGSEGV, Segmentation fault. 0x75de43df in strlen () from C:\Windows\syswow64\msvcrt.dll (gdb) where #0 0x75de43df in strlen () from C:\Windows\syswow64\msvcrt.dll #1 0x00404dd7 in __pformat_puts (stream=0x28fdfc, s=0x73617263 <Address 0x73617263 out of bounds>) at ../mingwrt-4.0.3-1-mingw32-src/misc/src/libcrt/stdio/pformat.c:338 #2 __mingw_pformat (flags=flags@entry=0, dest=dest@entry=0x28fe80, max=max@entry=79, fmt=0x40a06c <__register_frame_info+4235372> "", fmt@entry=0x40a06a <__register_frame_info+4235370> "%s", argv=0x40a068 <__register_frame_info+4235368> "h", argv@entry=0x40a064 <__register_frame_info+4235364> "crash") at ../mingwrt-4.0.3-1-mingw32-src/misc/src/libcrt/stdio/pformat.c:1786 #3 0x00402c18 in __mingw_vsnprintf (buf=0x28fe80 "ŠŠ(", length=79, fmt=0x40a06a <__register_frame_info+4235370> "%s", argv=0x40a064 <__register_frame_info+4235364> "crash") at ../mingwrt-4.0.3-1-mingw32-src/src/libcrt/stdio/vsnprintf.c:58 #4 0x00401706 in polyCrash ( format=0x40a06a <__register_frame_info+4235370> "%s", arg=0x40a064 <__register_frame_info+4235364> "crash") at src/main.cpp:22 #5 0x0040172a in main (argc=1, argv=0xa12b28) at src/main.cpp:31 (gdb) |
From: Keith M. <kei...@us...> - 2013-12-31 10:34:51
|
On 30/12/13 01:26, curt wrote: > Just ported some libraries of mine to a new project and one of the > well-used one choked and died. After some sluthing I found the problem > appears to be thing mingw linker getting confused on what to call. This is an incorrect conclusion, I think; your issue, on the basis of the evidence you provide here, has nothing whatsoever to do with the linker being confused, (or doing anything untoward). > Simplified example: Which isn't even compilable ... but after fixing it > #include <stdio.h> > #include <stdarg.h> > > void polyCrash( const char* format, ... ) > { > va_list arg; > va_start( arg, format ); > char buf[80]; > vsnprintf( buf, 80, format, arg ); > va_end( arg ); > } > > void polyCrash( const char* format, va_list arg ) > { > char buf[80]; > vsnprintf( buf, 80, format, arg ); > } > > int main( int argc,char *argv[] ) > { such that this invalid (incomplete) statement > polyCrash( "%s", (char *)"crash" becomes polyCrash( "%s", (char *)"crash" ); and also adding return 0; to make the function pedantically complete > } > > compile with a simple: gcc -o t test.cpp and instead, compiling with mingw32-g++ -S test.cpp (I'm using a Linux hosted cross compiler; hence the mingw32- prefix), inspection of the generated assembly code indicates: 1) Your void "polyCrash( const char *, ... );" form of the overridden function is given a C++ mangled name of "__Z9polyCrashPKcz" 2) The "void polyCrash( const char *, va_list );" alternative is given the mangled name "__Z9polyCrashPKcPc". For reference, each of these mangled names is consistently reproduced by both G++-3.4.5 and G++-4.8.1 cross compiler variants, and also by a G++-4.7.2 native variant running on a Win7 VM; the corresponding names generated by the native G++-4.7.3 compiler, on the Linux host itself, are "_Z9polyCrashPKcz" and "_Z9polyCrashPKcP13__va_list_tag" respectively. A visual analysis of those mangled names may hint at the problem, but before going on to discuss it, I feel obliged to point out that your function overrides are ambiguous by design; this should probably be considered an extremely ill advised coding choice on your part, since the variant argument form will always represent a viable candidate to match any call to the va_list form. That said, the "__Z9polyCrashPKcPc" name, as generated by the mingw32 targetting variants of G++, does seem to be wrong, as confirmed by $ mingw32-c++filt __Z9polyCrashPKcPc polyCrash(char const*, char*) This represents a function signature which does not match your source void polyCrash( const char *format, va_list arg ) (a va_list is *not* a char*, yet this is how mingw32-g++ has compiled it); however, it does *exactly* match your usage in polyCrash( "%s", (char *)"crash" ); Hence, this exact match results in the *compiler*, (not the linker), choosing to call the va_list form of your polyCrash() function, when it compiles this statement in main(); since this function expects an *indirect* pointer reference, where it has been given a *direct* pointer reference, your program crashes with a segmentation fault, due to the dereference of an invalid pointer. You may wish to file a bug report at http://gcc.gnu.org/bugzilla/ in respect of the inappropriately generated C++ name mangling for va_list arguments, in mingw32 builds of G++. However, since this has been a consistent feature of all three versions I've checked, and therefore probably significantly more (perhaps even all) previous versions, you should also seriously consider eliminating the potentially ambiguous (and hence confusing) variant argument forms of function overrides, (where the variant form may match one or more other override forms), from your own source code. -- Regards, Keith. |