Hi all, ya know, our QT_Thunk is such a wonderfully beautifully implementation, it's just marvelous... ...except for the fact that some programs decided to not play nice with it ! ;-) Some programs call QT_Thunk in a broken way, i.e. they don't reserve 0x40 bytes scratch buffer on the stack for QT_Thunk to do its magic there. As our QT_Thunk assumed that all programs use a fixed 0x40 bytes stack buffer, it based its destination function argument count on it, which led to *negative* function argument counts in case the QT_Thunk call happened without such a 0x40 scratch buffer. Thus QT_Thunk bombed in such cases. - always copy (almost) the whole stack space over to the 16bit stack instead of calculating some potentially bogus parameter count - add some comments (also about a DDJ article) AddWeb 5 Professional (free download) uses QT_Thunk() to thunk down to GetFreeSystemResources16(), and due to that crash and an exception handler it refused to load with a "not enough resources" error. This patch fixes it almost completely (except for crashes probably due to unimplemented flat scrollbars). Wonderfully complex program ! :) -- Andreas Mohr Stauferstr. 6, D-71272 Renningen, Germany Tel. +49 7159 800604 http://mohr.de.tt
Determining best CVS host... Using CVSROOT :pserver:cvs@rhlx01.fht-esslingen.de:/home/wine Index: dlls/kernel/thunk.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/thunk.c,v retrieving revision 1.27 diff -u -r1.27 thunk.c --- dlls/kernel/thunk.c 31 May 2002 23:25:48 -0000 1.27 +++ dlls/kernel/thunk.c 8 Jul 2002 16:29:28 -0000 @@ -299,9 +299,24 @@ * QT_Thunk (KERNEL32.@) * * The target address is in EDX. - * The 16 bit arguments start at ESP. + * The 16bit arguments start at ESP. * The number of 16bit argument bytes is EBP-ESP-0x40 (64 Byte thunksetup). + * So the stack layout is 16bit argument bytes and then the 64 byte + * scratch buffer. + * The scratch buffer is used as work space by Windows' QT_Thunk + * function. + * As the programs unfortunately don't always provide a fixed size + * scratch buffer (danger, stack corruption ahead !!), we simply resort + * to copying over the whole EBP-ESP range to the 16bit stack + * (as there's no way to safely figure out the param count + * due to this misbehaviour of some programs). * [ok] + * + * See DDJ article 9614c for a very good description of QT_Thunk (also + * available online !). + * + * FIXME: DDJ talks of certain register usage rules; I'm not sure + * whether we cover this 100%. */ void WINAPI QT_Thunk( CONTEXT86 *context ) { @@ -312,19 +327,35 @@ context16.SegCs = HIWORD(context->Edx); context16.Eip = LOWORD(context->Edx); + /* point EBP to the STACK16FRAME on the stack + * for the call_to_16 to set up the register content on calling */ context16.Ebp = OFFSETOF( NtCurrentTeb()->cur_stack ) + (WORD)&((STACK16FRAME*)0)->bp; - argsize = context->Ebp-context->Esp-0x40; + /* + * used to be (problematic): + * argsize = context->Ebp - context->Esp - 0x40; + * due to some programs abusing the API, we better assume the full + * EBP - ESP range for copying instead: */ + argsize = context->Ebp - context->Esp; + + /* ok, too much is insane; let's limit param count a bit again */ + if (argsize > 64) + argsize = 64; /* 32 WORDs */ memcpy( (LPBYTE)CURRENT_STACK16 - argsize, (LPBYTE)context->Esp, argsize ); + /* let's hope call_to_16 won't mind getting called with such a + * potentially bogus large number of arguments */ wine_call_to_16_regs_short( &context16, argsize ); context->Eax = context16.Eax; context->Edx = context16.Edx; context->Ecx = context16.Ecx; + /* make sure to update the Win32 ESP, too, in order to throw away + * the number of parameters that the Win16 function + * accepted (that it popped from the corresponding Win16 stack) */ context->Esp += LOWORD(context16.Esp) - ( OFFSETOF( NtCurrentTeb()->cur_stack ) - argsize ); }