[Bug 28753] New: AniDB O'Matic shows exception dialog on startup (madcodehook, gcc 4.6.x frame pointer omission in Wine code)

wine-bugs at winehq.org wine-bugs at winehq.org
Sun Oct 16 14:21:52 CDT 2011


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 at winehq.org
        ReportedBy: focht at 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/7e309601f3cb55deadaab9bd444757483a0fb065:/dlls/rpcrt4/rpc_server.c#l704

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

-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.



More information about the wine-bugs mailing list