[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