The main problem I'm looking at happens in battle_interface.dll. It's something that has to do with freeing the memory used by a vertex buffer. On my computer I've set up WinDbg to use Microsoft's symbol database. The operating system libraries show their names now, which is very nice.
The pieces of the puzzle left to identify are the three obscure battle_interface routines shown in the call stack below. Then I'll be able to determine the code in "PROGRAMS\Battle_Interface\BattleInterface.c" that triggers the problem. Ultimately, the root cause might be in the DLL, not how it's used in game... I tested the obvious thing already, commenting out "DeleteClass(&BattleInterface)" in BattleInterface.c - but that didn't prevent the library code from being triggered (nothing else I tried commenting out in BattleInterface.c has prevented triggering the code either).
Code:
(The top of the stack is the last thing being done by the program.)
(Each line down is an earlier routine, which called the next one up.)
0012f718 6efd9df2 verifier!VerifierStopMessage+0x1f8
0012f77c 6efda22a verifier!AVrfpDphReportCorruptedBlock+0x1c2
0012f7d8 6efda742 verifier!AVrfpDphCheckNormalHeapBlock+0x11a
0012f7f8 6efd90d3 verifier!AVrfpDphNormalHeapFree+0x22
0012f81c 77805674 verifier!AVrfDebugPageHeapFree+0xe3
0012f864 777c7aca ntdll!RtlDebugFreeHeap+0x2f
0012f958 77792d68 ntdll!RtlpFreeHeap+0x5d
0012f978 759174d9 ntdll!RtlFreeHeap+0x142
0012f9c0 6d7ba433 KERNELBASE!LocalFree+0x27
0012f9cc 6d7caf08 d3d8!MemFree+0x13
0012f9d8 6d80d1ac d3d8!operator delete+0x18
0012f9f4 6d80b01b d3d8!CBuffer::~CBuffer+0x3c
0012fa04 6d816e24 d3d8!CVertexBufferMT::`scalar deleting destructor'+0x2b
0012fa14 6d80b7c8 d3d8!CBaseObject::ReleaseImpl+0x34
0012fa24 045c694b d3d8!CMipVolume::Release+0x38
WARNING: Stack unwind information not available. Following frames may be wrong.
0012fa3c 020be241 DX8RENDER!DMAInterface+0x477b (this is DX8RENDER!ReleaseVertexBuffer)
0012fa4c 020bfe40 battle_interface+0xe241
0012fa68 020bfdc8 battle_interface!DMAInterface+0x940
0012fa70 004186c0 battle_interface!DMAInterface+0x8c3
0012fd64 004147db ENGINE+0x186c0
I created a temporary patch, which should work for everyone (attached to this post is "BI_bypassFDC0.7z"). The patch skips the code in "battle_interface.dll" that leads to memory corruption. I've noticed an improvement in game stability, but this patch trades memory corruption for a potential memory leak instead (kinda like what FTH does, except very constant and precise). Once I figure out what the last routines are, I'll come up with a better solution for it.
battle_interface.dll file offset 0xFDC0 was 56, changed to C3.
----------
I might've found a second bug in the game. I haven't identified it by name yet, but a missing texture gets used by the game sometimes in sailing mode (in vanilla PotC). This causes accelerated SSE2/MMX texture blitting on my computer to crash when it trys using it. It seems to depend on a random sailing event.
----------
I've started working on naming all the routines in DX8RENDER.dll and battle_interface.dll. Doing all the game modules would take months, so I'm holding off on the rest until I need them or I can find time. When I have a mostly complete list of names, I can turn them into debugging symbols. An example of the benefit to doing this is in the call stack shown above, I determined DX8RENDER!DMAInterface+0x477b is in fact a routine named DX8RENDER!ReleaseVertexBuffer. A few of the names like this one were revealed by looking for exception handling text stored in the DX8RENDER.dll. Most of the routines aren't this easy though, they have to be named by figuring out what the code does or what system libraries it calls.
----------
While digging in files with a hex editor, I found the names of the built-in functions for the game's programming language. I wrote them down as a comprehensive reference manual for myself, but I haven't determined most of the parameters and return values. This is probably already known to modders, but I thought I should share it in case it wasn't (or in case some of the functions were missed).
I was hoping to find a command like Breakpoint() that would drop into the debugger I'm using. That command is meant for a debugger built into the game though, not a separate one like WinDbg (so it does nothing but freeze the game when used). I'm thinking about trying to modify engine.exe so that Breakpoint() triggers a real application interrupt. That'd help a lot.