https://bugs.winehq.org/show_bug.cgi?id=45194
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEEDINFO Ever confirmed|0 |1 URL|https://www.fileplanet.com/ |https://web.archive.org/web |143135/download/Painkiller- |/20210225180649/http://down |Multiplayer-Demo |load.fileplanet.com/ftp1/07 | |2004/PainkillerMultiplayerD | |emo.exe?st=AWUh90d40OPmo7ws | |ul3CIg&e=1614287119
--- Comment #24 from Anastasius Focht focht@gmx.net --- Hello folks,
adding stable download link via Internet Archive:
https://web.archive.org/web/20210225180649/http://download.fileplanet.com/ft...
I've tried to reconstruct the code flow using OP's backtrace from comment #16 and a debugger.
--- snip --- wine: Unhandled division by zero at address 0x100013d3 (thread 0009), starting debugger... Unhandled exception: divide by zero in 32-bit code (0x100013d3). Register dump: CS:0023 SS:002b DS:002b ES:002b FS:006b GS:0063 EIP:100013d3 ESP:0032f9b4 EBP:00000000 EFLAGS:00210246( R- -- I Z- -P- ) EAX:0eac62d3 EBX:ffffffff ECX:00976340 EDX:00554a30 ESI:00974850 EDI:01f5ad70 Stack dump: 0x0032f9b4: 0000007f 002adb42 1001b71f 00974850 0x0032f9c4: 00402a19 00976338 00974850 0032fb18 0x0032f9d4: 00440e5b 00000000 1004c61d 00000000 0x0032f9e4: 00b8a315 00976338 ffffffff 01f1c7f8 0x0032f9f4: 00000001 003b0008 00000000 003f7b90 0x0032fa04: 00000000 00000000 00000000 00000000 Backtrace: =>0 0x100013d3 in engine (+0x13d3) (0x00000000) 0x100013d3: divl 0x4(%esp),%eax --- snip ---
0x1004c61d:
--- snip --- 1004C5F4 | mov dword ptr ss:[esp+140],ebx | 1004C5FB | mov dword ptr ds:[esi+D8],eax | 1004C601 | cmp dword ptr ds:[esi+DC],ebp | 1004C607 | mov dword ptr ds:[esi+EC],2 | 1004C611 | jne engine.1004C7DF | 1004C617 | call dword ptr ds:[<?OurGame@@3P6APAVEngineGame@@XZA>] | <--- 1004C61D | push 17E4 | 1004C622 | mov dword ptr ds:[esi+DC],eax | 1004C628 | call engine.1025181B | --- snip ---
0x00402a19:
--- snip --- 004029E0 | push FFFFFFFF | 004029E2 | push painkillerdemo.440E5B | 004029E7 | mov eax,dword ptr fs:[0] | 004029ED | push eax | 004029EE | mov dword ptr fs:[0],esp | 004029F5 | push ecx | 004029F6 | push esi | 004029F7 | push 1C | 004029F9 | call painkillerdemo.42E51B | 004029FE | mov esi,eax | 00402A00 | add esp,4 | 00402A03 | mov dword ptr ss:[esp+4],esi | 00402A07 | xor eax,eax | 00402A09 | cmp esi,eax | 00402A0B | mov dword ptr ss:[esp+10],eax | 00402A0F | je painkillerdemo.402A21 | 00402A11 | mov ecx,esi | 00402A13 | call dword ptr ds:[<&??0EngineGame@@QAE@XZ>] | <--- 00402A19 | mov dword ptr ds:[esi],painkillerdemo.4449E0 | 00402A1F | mov eax,esi | 00402A21 | mov ecx,dword ptr ss:[esp+8] | 00402A25 | pop esi | 00402A26 | mov dword ptr fs:[0],ecx | 00402A2D | add esp,10 | 00402A30 | ret | --- snip ---
0x1001b71f:
--- snip --- 1001B700 | push esi | 1001B701 | mov esi,ecx | 1001B703 | xor al,al | 1001B705 | mov dword ptr ds:[esi],<engine.??_7EngineGame@@6B@> | 1001B70B | mov byte ptr ds:[esi+10],al | 1001B70E | mov byte ptr ds:[esi+11],al | 1001B711 | mov ecx,dword ptr ds:[<?GEngine@@3PAVPCFSystem@@A>] | 1001B717 | add ecx,8 | 1001B71A | call <engine.?GetCurrentTimeMS@SystemDriver@@QBEKXZ> | <--- 1001B71F | mov dword ptr ds:[esi+14],eax | 1001B722 | mov eax,esi | 1001B724 | pop esi | 1001B725 | ret | --- snip ---
0x100013d3:
demangled class member function name:
public: unsigned long __thiscall SystemDriver::GetCurrentTimeMS(void) const
--- snip --- 10001390 | sub esp,8 | 10001393 | fld st(0),qword ptr ds:[10278538] | st(0) = 0.001 10001399 | sub esp,8 | 1000139C | fdiv st(0),qword ptr ds:[ecx+48] | st(0) / this->dblUnkVal 1000139F | fstp qword ptr ss:[esp],st(0) | st(0) -> arg0 100013A2 | call engine.10251B50 | floor(arg0) 100013A7 | fnstcw word ptr ss:[esp+8] | 100013AB | movzx eax,word ptr ss:[esp+8] | 100013B0 | add esp,8 | 100013B3 | or ah,C | 100013B6 | mov dword ptr ss:[esp+4],eax | 100013BA | fldcw word ptr ss:[esp+4] | x87ControlWord = 0xC7F 100013BE | fistp dword ptr ss:[esp+4],st(0) | var = (int) st(0) 100013C2 | mov eax,dword ptr ss:[esp+4] | 100013C6 | mov dword ptr ss:[esp+4],eax | 100013CA | fldcw word ptr ss:[esp] | 100013CD | xor eax,eax | 100013CF | xor edx,edx | 100013D1 | rdtsc | 100013D3 | div dword ptr ss:[esp+4] | div by zero 100013D7 | mov dword ptr ss:[esp],eax | 100013DA | mov eax,dword ptr ss:[esp] | 100013DD | add esp,8 | 100013E0 | ret | --- snip ---
0x10278538 dq 0.001 == constant
ECX: 0x01887188 (dynamic driver class instance (+8) on heap)
--- snip --- $ ==> 01887188 01B43380 $+4 0188718C 00000001 ... $+48 018871D0 3490CDC1 $+4C 018871D4 3DFCB31C --- snip ---
[ecx+48] = [018871D0] = this->dblUnkVal = 4.17635e-10
after floor(arg0): st(0) = 40149225100000000000 -> 2394435.0 (int) st(0) -> 2394435
'GetCurrentTimeMS' subroutine essentially does this:
rdtsc() / (int) floor(0.001 / this->dblUnkVal);
floor = round down the nearest integer
0.001 is an engine constant hence you only get division by zero if 'this->dblUnkVal' > 0.001
This is assuming that 'this->dblUnkVal' == 0.0 case doesn't occur.
===
Tidbit: Using the subroutine name I found the following reference:
https://raw.githubusercontent.com/SuiMachine/LiveSplit.ASLScripts/master/Pai...
--- snip --- state("painkiller", "Steam") { //To find addresses, reverse LoadingScreen::Render and get GEngine address for that //"Engine.dll", 0x4FEBE68 -> *PCFSystem
//Then X-ref back to World::Init. There you can find a first offset for GEngine and a bool value //Do keep in mind that for example IDA says *((_DWORD *)GEngine + 0x3C), but it's a DWORD, so it's 4 times 3C, so 0xF0 (now we base and offset) //"Engine.dll", 0x4FEBE68, 0xF0
//Now find LoadingScreen::Progress(v23, 1) in that function and get pointer for a bool value from that //"Engine.dll", 0x4FEBE68, 0xF0, 0x5D6BD4 -> *LoadingScreen (identical case for other games, just different offsets) //"Engine.dll", 0x4FEBE68, 0xF0, 0x5D6BD4, 0x88-> Bool value telling whatever loading is happening
//And then if you want to be bothered there is: //"Engine.dll", 0x4FEBE68, 0xF0, 0x5D6BD4, 0x88 + 0xC-> Float value for the progress indicator (aka % of completion - but we don't use it) bool pLoadingScreen : "Engine.dll", 0x4FEBE68, 0xF0, 0x5D6BD4, 0x88;
//To get a tick, find an extern function PCFSystem::TickEngine //In it, somewhere after middle you'll find a call to a function SystemDriver::GetCurrentTimeMS //It returns the time in MS and above has an int variable that is getting incremeneted with each tick and is set to 0 (below one of the calls to SystemDriver::GetCurrentTimeMS) int pTick : "Engine.dll", 0x3E9D2C;
//Name of a level you get by solving out pointer in World::Init string25 pLevelName : "Engine.dll", 0x4FEBE68, 0xE8, 0x01888, 0x0; } --- snip ---
It doesn't tell more information I already had gathered though.
I could try to track all write accesses to the member variable (class instance on heap) and check how a condition > 0.001 could be reached from various code paths but that's wasting a bit too much time for my taste with little value gain. Maybe if I run out of more interesting bugs which likely never happens.
Maybe OP can retest again with recent Wine 6.x release?
$ wine --version wine-6.2-360-g1649389edca
Regards