win16 app fails with multiple c0000005 exceptions

Questions about Wine on macOS.
Post Reply
Dirk Niggemann
Posts: 2
Joined: Tue Jan 21, 2020 4:04 pm

win16 app fails with multiple c0000005 exceptions

Post by Dirk Niggemann » Wed Jan 22, 2020 5:46 pm

I'm tying to run a very old 'mixed' win16 / win32 app- Agilent Chemstation G1701BA from about 2000. It was 'certified' to run on NT4 systems and still runs on windows 10/32 with some peculiar tweaks (requires disabling write access to root of C:\) but nothing that i see relevant to this report.

This software is designed to control older Agilent GC/MS systems which are no longer supported with newer versions of the same software.

Basically a few of the components are win16 apps and the others are win32. The win32 data analysis component (MSDA.EXE) runs OK on Wine 5.0-rc6 on Mac with no major issues other than that the file dialog not allowing you to select the application's 'files' which are actually directories. You can still type the name of the directory manually and it will load the contents correctly.

However, the configuration program (MSCONFIG.EXE) which is win16 crashes on startup.

Having resolved one issue with argument marshalling in win16-32 cross calling (see the program now starts but fails to display its menu bar.

The actual he GCMS control program (MSTOP.EXE) is also 16-bit and does not load its menus either, but this doesn’t crash on startup.

As both programs include an interpreter for Chemstation macros, the menus are dynamically programmable. The configuration file that controls the menus errors in a builtin routine called MENUEND. It appears the error handling is internally represented by structured exceptions.

Both programs exhibit the same issues when started with WINEDEBUG=+relay,+menu,+seh,+global.

Exceptions of the following form:

Code: Select all

002c:Ret  KERNEL.19: GLOBALUNLOCK() retval=00000000 ret=12af:13ce ds=1336
002c:trace:global:GlobalHandle16 1017
002c:Call KERNEL.17: GLOBALFREE(16be) ret=12af:13d6 ds=1336
002c:trace:global:GlobalFree16 16be
002c:Call KERNEL32.HeapFree(00540000,00000000,005d3498) ret=6ab660cb
002c:Ret  KERNEL32.HeapFree() retval=00000001 ret=6ab660cb
002c:Ret  KERNEL.17: GLOBALFREE() retval=00000000 ret=12af:13d6 ds=1336
002c:trace:seh:raise_exception code=c0000005 flags=0 addr=0x6ab5e7c9 ip=6ab5e7c9 tid=002c
002c:trace:seh:raise_exception  info[0]=00000000
002c:trace:seh:raise_exception  info[1]=000016b8
002c:trace:seh:raise_exception  eax=00000000 ebx=00000000 ecx=00000000 edx=16bf0000 esi=000002b6 edi=000046ce
002c:trace:seh:raise_exception  ebp=00004b4a esp=0000452a cs=001b ds=1336 es=0023 fs=11cf gs=000f flags=00010202
Each exception occurs at least twice, immediately after GLOBALFREE() each time.

When run in winedbg, I see the following:

Code: Select all

0038:err:thunk:K32WOWHandle16 handle 0x10072 of type 0 has non-zero HIWORD
First chance exception: page fault on read access to 0x000016b8 in 32-bit code (0x000000006b0147c9).
Register dump:
 CS:001b SS:1337 DS:1336 ES:0023 FS:11cf GS:000f
 EIP:6b0147c9 ESP:0000452a EBP:00004b4a EFLAGS:00010246(  R- --  I  Z- -P- )
 EAX:00000000 EBX:00000000 ECX:00000000 EDX:16bf0000
 ESI:000002b6 EDI:000046ce
Bad segment (4919)
Stack dump:
=>0 0x000000006b0147c9 __wine_call_from_16+0x91() in krnl386.exe16 (0x0000000000000000)
0x000000006b0147c9 __wine_call_from_16+0x91 in krnl386.exe16: pop %es
This occurs for every exception with only the address of the exception being different. SS is always 0x1337 and DS 0x1336.

It appears that the exception occurs in one of the automatically built thunks defined in winebuild. When tracing, this seems to be on return from GlobalFree16. It’s popping an invalid segment descriptor into DS just before the pop %es. This is segment 0x1337.

I think the err:thunk is irrelevant because the same error occurs in the working MSDA program, and doesn’t occur immediately adjacent to the exceptions.

The problem I am having is that I can’t figure out how to debug through the thunks and the following additional challenges apply:

The exception occurs only after certain GlobalFree16 calls, not all of them,
All the internal calls in GlobalFree16 (such as to HeapFree) appear to succeed.
Looking at the handle usage with +global, the handle 16be is allocated, locked and unlocked in what appears to be a valid sequence.
The exception occurs after calls to GLOBALFREE() with different handles- It’s not just one specific corrupt memory area or handle.

Can anybody suggest how I go about debugging this further?
Is the segment number 1337 significant? Or is a ‘leet’ segment descriptor just a coincidence?

Is this some sort of handle to segment descriptor conversion bug?

Dirk Niggemann
Posts: 2
Joined: Tue Jan 21, 2020 4:04 pm

Re: win16 app fails with multiple c0000005 exceptions

Post by Dirk Niggemann » Sun Jan 26, 2020 6:25 am

Just did some further analysis - I'm pretty sure the c0000005 exceptions are a red herring caused by freeing a selector that is still referenced in %es. I think the pop %es exceptions trying to restore the selector that was just freed.

Temporarily removing the wine_ldt_free_entries( ) call in FreeSelector() stops the exceptions but doesn't fix the program.

In either case it does something extremely strange using toolhelp.dll, calling LOCALFIRST() and LOCALNEXT() to walk its own local heap. I originally thought this was it trying to report on its own internal errors but appears it does it even if no exceptions are raised.

I think the wine implementation of toolhelp.dll is sufficiently different to the windows one to trigger the failure to display menus in some way I don't yet understand. All I know is that it never gets as far calling SetMenu() for the menus that it builds.

Post Reply