http://bugs.winehq.org/show_bug.cgi?id=13411
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |focht@gmx.net
--- Comment #3 from Anastasius Focht focht@gmx.net 2008-12-18 17:11:14 --- Hello,
you only need a clean WINEPREFIX and msxml4 as prerequisite.
sh winetricks msxml4
---
The app is delphi 6/7 based, making heavy use of the TNT UnicodeControls toolkit which adds unicode capability for the standard VCL controls.
The crash happens while destroying an MDI child form as outlined in steps from comment #1
In the destroy message handler, the window/control text gets retrieved from (subclassed) controls.
First, the text length is determined by sending WM_GETTEXTLENGTH message. Then a buffer is allocated with determined length and lastly the control text is captured into buffer. Unfortunately that doesn't work out as expected ...
--- snip --- ... 0009:Call window proc 0xdf0d99 (hwnd=0x1011c,msg=WM_DESTROY,wp=00000000,lp=00000000) 0009:Call user32.SendMessageA(0001011c,0000000e,00000000,00000000) ret=004d1be0 0009:Call hook proc 0x580390 (id=WH_CALLWNDPROC,code=0,wp=00000001,lp=0032da94) 0009:Call user32.CallNextHookEx(00010046,00000000,00000001,0032da94) ret=0058040d 0009:Ret user32.CallNextHookEx() retval=00000000 ret=0058040d 0009:Ret hook proc 0x580390 (id=WH_CALLWNDPROC,code=0,wp=00000001,lp=0032da94) retval=00000000 0009:trace:msg:WINPROC_CallProcAtoW (hwnd=0x1011c,msg=WM_GETTEXTLENGTH,wp=00000000,lp=00000000) 0009:Call window proc 0xdf0d8c (hwnd=0x1011c,msg=WM_GETTEXTLENGTH,wp=00000000,lp=00000000) 0009:Call user32.CallWindowProcW(00df0d99,0001011c,0000000e,00000000,00000000) ret=004d1851 0009:Call window proc 0xdf0d99 (hwnd=0x1011c,msg=WM_GETTEXTLENGTH,wp=00000000,lp=00000000) 0009:Ret window proc 0xdf0d99 (hwnd=0x1011c,msg=WM_GETTEXTLENGTH,wp=00000000,lp=00000000) retval=00000000 0009:Ret user32.CallWindowProcW() retval=00000000 ret=004d1851 0009:Ret window proc 0xdf0d8c (hwnd=0x1011c,msg=WM_GETTEXTLENGTH,wp=00000000,lp=00000000) retval=00000000 0009:Call window proc 0xdf0d8c (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) 0009:Call user32.CallWindowProcW(00df0d99,0001011c,0000000d,00000001,0032d4fc) ret=004d1851 0009:Call window proc 0xdf0d99 (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) 0009:Call user32.CallWindowProcA(00df0d7f,0001011c,0000000d,00000001,0032d4fc) ret=00471ecc 0009:Call window proc 0xdf0d7f (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) 0009:Call user32.CallWindowProcW(60650fb2,0001011c,0000000d,00000001,0032d4fc) ret=004d1a55 0009:Call window proc 0x60650fb2 (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) 0009:Call user32.GetWindowLongW(0001011c,00000000) ret=60650fd7 0009:Ret user32.GetWindowLongW() retval=001ca680 ret=60650fd7 0009:trace:statusbar:StatusWindowProc hwnd=0x1011c msg=d wparam=1 lparam=32d4fc 0009:trace:statusbar:STATUSBAR_WMGetText 0009:Ret window proc 0x60650fb2 (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) retval=ffffffff 0009:Ret user32.CallWindowProcW() retval=ffffffff ret=004d1a55 0009:Ret window proc 0xdf0d7f (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) retval=ffffffff 0009:Ret user32.CallWindowProcA() retval=ffffffff ret=00471ecc 0009:Ret window proc 0xdf0d99 (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) retval=ffffffff 0009:Ret user32.CallWindowProcW() retval=ffffffff ret=004d1851 0009:Ret window proc 0xdf0d8c (hwnd=0x1011c,msg=WM_GETTEXT,wp=00000001,lp=0032d4fc) retval=ffffffff 0009:Ret user32.SendMessageA() retval=7fffffff ret=004d1be0 0009:trace:seh:raise_exception code=c0000005 flags=0 addr=0x40e5ed 0009:trace:seh:raise_exception info[0]=00000001 0009:trace:seh:raise_exception info[1]=00000000 0009:trace:seh:raise_exception eax=00000000 ebx=80000004 ecx=00000000 edx=7fffffff esi=7fffffff edi=0032de08 0009:trace:seh:raise_exception ebp=0032dd50 esp=0032dc10 cs=0023 ds=002b es=002b fs=0063 gs=006b flags=00210246 ... 0009:Call oleaut32.SysAllocStringLen(0032c658 L"Access violation at address 0040E5ED in module 'Teach2000.exe'. Write of address 00000000",00000059) ret=00405cc0 --- snip ---
The user control exhibiting the problem: a TTntStatusBar statusbar (unicode) control, subclassed from standard VCL one
--- snip --- 0009:Call user32.CreateWindowExW(00000000,001b89c4 L"TTntStatusBar.UnicodeClass",00000000,44000001,00000000,00000246,000004e4,00000013,0002010e,00000000,00400000,00000000) ret=00408e54 0009:trace:win:WIN_CreateWindowEx (null) L"TTntStatusBar.UnicodeClass" ex=00000000 style=44000001 0,582 1252x19 parent=0x2010e menu=(nil) inst=0x400000 params=(nil) 0009:trace:win:dump_window_styles style: WS_CHILD WS_CLIPSIBLINGS 00000001 0009:trace:win:dump_window_styles exstyle: 0009:trace:win:WIN_SetWindowLong 0x1011c -12 0 W --- snip ---
If you look at the return value from last SendMessage() call before the exception, 0x7fffffff is returned. This value ought to be the control text length which is obviously wrong. The VCL allocator can't allocate such a huge amount of memory, resulting in internal access violation.
The WM_GETTEXTLENGTH retrieval through default handlers in WINPROC_CallProcAtoW is correct, the result (text length) has to be zero for this control.
But the following code is somewhat buggy...
Even with zero length determined, WM_GETTEXT gets called. The (l)results from callback/SendMessage - which might be negative(!) - are passed unchecked to RtlUnicodeToMultiByteSize() which happily calculates incorrect length. That's what this delphi app stumbles about.
--- dlls/user32/wndproc.c snip --- LRESULT WINPROC_CallProcAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result, void *arg, enum wm_char_mapping mapping ) {
... case WM_GETTEXTLENGTH: case CB_GETLBTEXTLEN: case LB_GETTEXTLEN: ret = callback( hwnd, msg, wParam, lParam, result, arg ); if (*result >= 0) { WCHAR *ptr, buffer[512]; LRESULT tmp; DWORD len = *result + 1; /* Determine respective GETTEXT message */ UINT msgGetText = (msg == WM_GETTEXTLENGTH) ? WM_GETTEXT : ((msg == CB_GETLBTEXTLEN) ? CB_GETLBTEXT : LB_GETTEXT); /* wParam differs between the messages */ WPARAM wp = (msg == WM_GETTEXTLENGTH) ? len : wParam;
if (!(ptr = get_buffer( buffer, sizeof(buffer), len * sizeof(WCHAR) ))) break;
if (callback == call_window_proc) /* FIXME: hack */ callback( hwnd, msgGetText, wp, (LPARAM)ptr, &tmp, arg ); else tmp = SendMessageW( hwnd, msgGetText, wp, (LPARAM)ptr ); RtlUnicodeToMultiByteSize( &len, ptr, tmp * sizeof(WCHAR) ); *result = len; free_buffer( buffer, ptr ); } break;
... } --- dlls/user32/wndproc.c snip ---
Either skip the text retrieval for length == 0 (whats the reason anyway?) or check the return value from XX_GETTEXT before determining the byte buffer length.
I already verified with a patch, the app doesn't crash then.
Regards