http://bugs.winehq.org/show_bug.cgi?id=12902
--- Comment #1 from Anastasius Focht focht@gmx.net 2008-05-02 04:01:20 --- Hello,
no need for regression testing .. I'm faster debugging it than you do regression testing ;-)
There is a RegisterClassExA call in app code which looks pretty brain damaged. The app initializes the stack (structures) with 0xCCCCCCCC before writing to structure members.
The first call to RegisterClassA() succeeds, lpWndClass members (stack dump) before the call:
--- snip lpWndClass --- 0033F8E0 00000000 ; style 0033F8E4 00401C80 ; lpfnWndProc 0033F8E8 00000000 ; cbClsExtra 0033F8EC 00000000 ; cbWndExtra 0033F8F0 00400000 ; hInstance 0033F8F4 00001126 ; hIcon 0033F8F8 000010DE ; hCursor 0033F8FC 00000000 ; hbrBackground 0033F900 005E2000 ; lpszMenuName -> "Main" 0033F904 005E4BA5 ; lpszClassName -> "Furnish Pro" --- snip lpWndClass ---
The next call immediately following is RegisterClassExA(). Note: only the cbSize member is explicitly initialized!
WNDCLASSEXA* = 0x0033F908
--- snip --- 0033F908 00000030 ; cbSize (+0x0) 0033F90C CCCCCCCC ; style (+0x4) 0033F910 CCCCCCCC ; lpfnWndProc (+0x8) 0033F914 CCCCCCCC ; cbClsExtra (+0xC) 0033F918 CCCCCCCC ; cbWndExtra (+0x10) 0033F91C CCCCCCCC ; hInstance (+0x14) 0033F920 CCCCCCCC ; hIcon 0033F924 CCCCCCCC ; hCursor 0033F928 CCCCCCCC ; hbrBackground 0033F92C CCCCCCCC ; lpszMenuName 0033F930 CCCCCCCC ; lpszClassName 0033F934 00001126 ; hIconSm --- snip ---
This ought to fail in Windows with last error ERROR_INVALID_PARAMETER. After that call, the app initializes all other struct members and RegisterClassExA is called again, now succeeding.
The offending code in wine user32:
--- snip dlls/user32/class.c --- ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc ) { .. if (wc->hInstance == user32_module) { /* we can't register a class for user32 */ SetLastError( ERROR_INVALID_PARAMETER ); return 0; } if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
if (!IS_INTRESOURCE(wc->lpszClassName)) { WCHAR name[MAX_ATOM_LEN + 1];
if (!MultiByteToWideChar( CP_ACP, 0, wc->lpszClassName, -1, name, MAX_ATOM_LEN + 1 )) return 0; classPtr = CLASS_RegisterClass( name, instance, !(wc->style & CS_GLOBALCLASS), wc->style, wc->cbClsExtra, wc->cbWndExtra ); } else { classPtr = CLASS_RegisterClass( (LPCWSTR)wc->lpszClassName, instance, !(wc->style & CS_GLOBALCLASS), wc->style, wc->cbClsExtra, wc->cbWndExtra ); } if (!classPtr) return 0; ... } --- snip dlls/user32/class.c ---
It crashes by accessing pointer style members - not expecting garbage ;-) Same applies to "W" version.
Interestingly this application bug doesn't trigger page fault in windows. The culprit is probably the order of structure member evaluation.
"classExtra" and "winExtra" are possible non-pointer candidates to work around this problem without introducing another (unnecessary) SEH guard. Unfortunately these members are checked at relatively late stage in wine (CLASS_RegisterClass). If you move the code into appropriate functions, this app bug is worked around (yes, code small duplication but well).
--- snip example fix --- diff --git a/dlls/user32/class.c b/dlls/user32/class.c index ff0e1f8..d39350c 100644 --- a/dlls/user32/class.c +++ b/dlls/user32/class.c @@ -526,6 +526,13 @@ ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc ) CLASS *classPtr; HINSTANCE instance;
+ /* Fix the extra bytes value */ + if (wc->cbClsExtra < 0 || wc->cbWndExtra < 0) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return NULL; + } + if (wc->hInstance == user32_module) --- snip example fix ---
The app then starts loading, displaying main windows and splash screen and then crashes again due other wine bugs. While looking at the generated stack frame code it seems the compiler used 0xCC CCCCCC initialization values for all stack frame members. Thus other crashes are probably related to this fact.
If you need help for other crashes, call me again .. but fix this one first.
Regards