[Bug 45194] Painkiller game crashes at start
WineHQ Bugzilla
wine-bugs at winehq.org
Thu Feb 25 14:46:39 CST 2021
https://bugs.winehq.org/show_bug.cgi?id=45194
Anastasius Focht <focht at 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 at gmx.net> ---
Hello folks,
adding stable download link via Internet Archive:
https://web.archive.org/web/20210225180649/http://download.fileplanet.com/ftp1/072004/PainkillerMultiplayerDemo.exe?st=AWUh90d40OPmo7wsul3CIg&e=1614287119
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 at 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 at 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/Painkiller/LiveSplit.Painkiller.asl
--- 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
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list