http://bugs.winehq.org/show_bug.cgi?id=28753
Bug #: 28753 Summary: AniDB O'Matic shows exception dialog on startup (madcodehook, gcc 4.6.x frame pointer omission in Wine code) Product: Wine Version: 1.3.30 Platform: x86 OS/Version: Linux Status: NEW Severity: normal Priority: P2 Component: -unknown AssignedTo: wine-bugs@winehq.org ReportedBy: focht@gmx.net Classification: Unclassified
Hello,
I recently switched to gcc 4.6.x based distro and encountered strange problems with "AniDB O'Matic" (http://anidb.net/ client) and possibly other apps.
The app crash handler catches a fault in startup phase and displays a rather exhaustive "crash analysis" dialog. The fault can be acknowledged and the app continues to load.
Tracing with +relay yields nothing - the crash never happens.
Without +relay but relevant debugging channels:
--- snip --- ... 0009:trace:ole:RemUnknown_Release 0x1aaa28 after: 4 0009:trace:ole:stub_manager_ext_addref added 5 refs to 0x1aac30 (oid 1), rc is now 5 0009:trace:ole:RPC_RegisterInterface ({00000131-0000-0000-c000-000000000046}) 0009:trace:ole:RPC_RegisterInterface Creating new interface 0009:trace:rpc:RpcServerRegisterIfEx (0x1aad34,(null),(nil),3,1234,(nil)) 0009:trace:rpc:RpcServerRegisterIf2 (0x1aad34,(null),(nil),3,1234,4294967295,(nil)) 0009:trace:rpc:RpcServerRegisterIf2 interface id: {00000131-0000-0000-c000-000000000046} 0.0 0009:trace:rpc:RpcServerRegisterIf2 transfer syntax: {00000000-0000-0000-0000-000000000000} 0.0 0009:trace:rpc:RpcServerRegisterIf2 dispatch table: 0x7e769c00 0009:trace:rpc:RpcServerRegisterIf2 dispatch table count: 1 0009:trace:rpc:RpcServerRegisterIf2 entry 0: 0x7e6a7010 0009:trace:rpc:RpcServerRegisterIf2 reserved: 0 0009:trace:rpc:RpcServerRegisterIf2 protseq endpoint count: 0 0009:trace:rpc:RpcServerRegisterIf2 default manager epv: (nil) 0009:trace:rpc:RpcServerRegisterIf2 interpreter info: (nil) 0009:trace:rpc:RPCRT4_start_listen 0009:trace:seh:raise_exception code=c0000005 flags=0 addr=0x44fed3 ip=0044fed3 tid=0009 0009:trace:seh:raise_exception info[0]=00000000 0009:trace:seh:raise_exception info[1]=000006bd 0009:trace:seh:raise_exception eax=000006b9 ebx=00404d74 ecx=00000000 edx=000006b9 esi=00000000 edi=7e63a728 0009:trace:seh:raise_exception ebp=0032f404 esp=0032f258 cs=0073 ds=007b es=007b fs=0033 gs=003b flags=00010a16 0009:trace:seh:call_vectored_handlers calling handler at 0x7dccdcf0 code=c0000005 flags=0 0009:trace:seh:call_vectored_handlers handler at 0x7dccdcf0 returned 0 0009:trace:seh:call_vectored_handlers calling handler at 0x7defb860 code=c0000005 flags=0 0009:trace:seh:call_vectored_handlers handler at 0x7defb860 returned 0 0009:trace:seh:call_stack_handlers calling handler at 0x45015e code=c0000005 flags=0 --- snip ---
By debugging I found the following:
--- snip --- Wine-dbg>bt Backtrace: =>0 0x0044fe24 in aom (+0x4fe24) (0x0033f43c) 1 0x7ed9cf31 CreateThread+0x4b(sa=(nil), stack=0, start=0x7e5f1640, param=0x1aa8c0, flags=0, id=0x0(nil)) [/home/focht/projects/wine/wine-git/dlls/kernel32/thread.c:54] in kernel32 (0x000006b9) 2 0x7e5f1883 RPCRT4_start_listen_protseq.isra+0x82() in rpcrt4 (0x000006b9) 3 0x7e5f1a00 RPCRT4_start_listen+0xdf(auto_listen=<is not available>) [/home/focht/projects/wine/wine-git/dlls/rpcrt4/rpc_server.c:749] in rpcrt4 (0x7e625720) 4 0x7e5f40c1 RpcServerRegisterIf2+0x170(IfSpec=0x1aabb4, MgrTypeUuid=(nil), MgrEpv=0x0(nil), Flags=0x3, MaxCalls=0x4d2, MaxRpcSize=0xffffffff, IfCallbackFn=(nil)) [/home/focht/projects/wine/wine-git/dlls/rpcrt4/rpc_server.c:1149] in rpcrt4 (0x00000000) --- snip ---
The app installs some hooks into win32 API using intrusive way.
No IAT/API entry/hotpatch is used .. it analyses the API code and patches calls.
Example:
"CreateThread" snippet:
--- snip original --- ... movl 0x38(%esp),%eax movl %eax,0xc(%esp) movl 0x34(%esp),%eax movl %eax,0x8(%esp) movl 0x30(%esp),%eax movl %eax,0x4(%esp) call 0x7edb1d80 CreateRemoteThread [/home/kernel32/thread.c:54] in kernel32: subl $28,%esp addl $40,%esp popl %ebx ret $0x18 --- snip original ---
--- snip patched --- ... movl 0x38(%esp),%eax movl %eax,0xc(%esp) movl 0x34(%esp),%eax movl %eax,0x8(%esp) movl 0x30(%esp),%eax movl %eax,0x4(%esp) call 0x0045029c subl $28,%esp addl $40,%esp popl %ebx ret $0x18 --- snip patched ---
Although questionable this works (even in earlier Wine versions). Further analysis reveals the app was written in Delphi and makes use of "madCodeHook/madExcept" library (http://madshi.net/).
The apps creates several threads which are initialized successfully. The problem is actually an RPC thread that gets created by Wine code.
See here:
http://source.winehq.org/git/wine.git/blob/7e309601f3cb55deadaab9bd444757483...
Disassembly of problematic snippet from function "RPCRT4_start_listen_protseq":
--- snip --- ... movl $0x6b9,%ebp movl $0x0,0x14(%esp) movl $0x0,0x10(%esp) movl %esi,0xc(%esp) movl %eax,0x8(%esp) movl $0x0,0x4(%esp) movl $0x0,0x0(%esp) call 0x7e5b9d68 CreateThread in rpcrt4 subl $24,%esp testl %eax,%eax ... --- snip ---
Upon entry of CreateRemoteThread "hook", the handler analyses the frame pointer (checks for non-zero) and tries to access the frame location. This fails because GCC emitted code that used EBP as general purpose register for return status (RPC_S_OUT_OF_RESOURCES) in caller. The fault due to EBP dereference is safely caught from app SEH and a dialog shown.
Additionally to the RPC thread problem the GUI shows issues which were previously not present: some treeview items are missing/rearranged.
I checked the comctl32/treeview code .. even did some tests with older Wine versions (1.3.0, 1.3.20) no regressions found - it behaved similar.
In short: these issues are the result of gcc 4.6+ now free to omit frame pointers on x86 (= default), see:
http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Optimize-Options.html
I fixed the problems by adding "-fno-omit-frame-pointer" to build flags. The app works as expected (thread hooks = ok, GUI issues = gone).
I suspect there will be more apps and games that use code that depends on frame pointer not being abused as general purpose register.
The question is: is it worth to hunt down all Wine code and decorate functions with "no optimize" attributes to keep frame pointer from being abused? E.g. something like this: __attribute__((optimize("-fno-omit-frame-pointer")))
Maybe "-fno-omit-frame-pointer" should be default if Wine x86 is built with gcc 4.6.
Regards
http://bugs.winehq.org/show_bug.cgi?id=28753
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |download, Installer URL| |http://static.anidb.net/cli | |ent/AOM_0.5.17.264.zip
--- Comment #1 from Anastasius Focht focht@gmx.net 2011-10-16 14:27:36 CDT --- Hello,
filling some fields...
Wine was built with defaults.
$ wine --version wine-1.3.30-145-g7a4349b
$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6.1/lto-wrapper Target: i686-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu Thread model: posix gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)
Regards
http://bugs.winehq.org/show_bug.cgi?id=28753
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |austinenglish@gmail.com
--- Comment #2 from Austin English austinenglish@gmail.com 2011-10-17 13:50:56 CDT --- FWIW, I filed a gcc bug for this about a year ago: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46468
http://bugs.winehq.org/show_bug.cgi?id=28753
--- Comment #3 from Anastasius Focht focht@gmx.net 2011-10-17 14:22:55 CDT --- Hello Austin,
--- quote --- FWIW, I filed a gcc bug for this about a year ago: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46468 --- quote ---
It was their decision to change the default behaviour for frame pointer optimizations starting with 4.6 series. It's very, very unlikely that the gcc folks will revert this for the sake of Wine.
If Wine depends on the previous behaviour ... it has to take care of this. The generated code is perfectly legal with changed default.
If there is application code, for example copy protection/obfuscation schemes that rely on valid frame pointer being present in certain API code, Wine needs to hint gcc using function annotation or by explicitly changing default behaviour to old state.
Regards
http://bugs.winehq.org/show_bug.cgi?id=28753
--- Comment #4 from Austin English austinenglish@gmail.com 2011-10-17 18:47:18 CDT --- Of course.
Though it seems that we may need both -fno-omit-frame-pointer and -fno-asynchronous-unwind-tables.
according to Marcus's comment: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46468#c8
FWIW, I compiled wine with a newish gcc (4.6.0 20100812 experimental), and tried winetest. All tests that normally pass for me still pass.
http://bugs.winehq.org/show_bug.cgi?id=28753
Austin English austinenglish@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Fixed by SHA1| |5cfe7db1854ff1142d598eaf49f | |6050676c8d547 Status|NEW |RESOLVED Resolution| |FIXED
--- Comment #5 from Austin English austinenglish@gmail.com 2011-10-19 14:11:48 CDT --- http://source.winehq.org/git/wine.git/commitdiff/5cfe7db1854ff1142d598eaf49f...
http://bugs.winehq.org/show_bug.cgi?id=28753
Alexandre Julliard julliard@winehq.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |CLOSED
--- Comment #6 from Alexandre Julliard julliard@winehq.org 2011-10-21 13:49:34 CDT --- Closing bugs fixed in 1.3.31.
http://bugs.winehq.org/show_bug.cgi?id=28753
Andrew Nguyen arethusa26@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |lukasz.wojnilowicz@gmail.co | |m
--- Comment #7 from Andrew Nguyen arethusa26@gmail.com 2011-10-21 14:27:29 CDT --- *** Bug 28266 has been marked as a duplicate of this bug. ***
http://bugs.winehq.org/show_bug.cgi?id=28753
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Component|-unknown |build-env
http://bugs.winehq.org/show_bug.cgi?id=28753
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Keywords| |obfuscation