halflife icon indicating copy to clipboard operation
halflife copied to clipboard

CStrike Hostage Crash (Nov./ Dec. 2023 Update)

Open ClaudiuHKS opened this issue 2 years ago • 2 comments

When rescuing hostages on cs_italy, the game crashes. Not instantly, but at some point, while the hostages are following you, it crashes. Especially if you turn around and duck, jump, make the hostages block each other ...

To reproduce, on cs_italy, while the four hostages are following you, jump on something, duck and move around while ducked but don't get back down where the hostages are waiting you, while the hostages are below you and they don't know how to reach you. The game server will then crash within a few seconds. HLDS.exe console (or the game itself i.e. New Game -> cs_italy) will freeze, surprisingly. Not exits.

ClaudiuHKS avatar Dec 17 '23 15:12 ClaudiuHKS

I can confirm that almost two years after the release this issue is still present. In my opinion it is a severe bug, which leads me to think that the game is unmaintained and the developers don't care about it anymore.

If anyone is having the same issue and reads this, the following video illustrates the method described by @ClaudiuHKS to trigger the bug:

https://youtu.be/tbER8Aj51vU

Anyway, despite my debugging capabilities are far from great, I've been able to locate the issue and "kind of" circumvent it. It's a quick and dirty hack, but it seems to get the job done.

When the game freezes, the process gets stuck inside a loop related to the hostages movement. At the end of that loop, the code calculates the magnitude of a vector and compares it to 1.0f, if it is smaller the loop ends. At some point, for reasons I'm not capable to figure out, one of the components of that vector is ridiculously high (in the order of 10e+30), and after squaring it, it becomes +INF. This makes the loop repeat endlessly, always giving the same result. To fix it, I simplified the way the math is done, to free some memory, and inserted an additional condition to check if the result is +INF, and in that case, change it to zero. This allows the program to continue, and it doesn't seem to introduce any adverse effect.

To apply the patch, edit "mp.dll", find the following pattern:

0F57C90F5AC0660F2EC87706F20F51C0EB05E8F2740700F20F5AC0

And replace in with:

F30F51C0660F7EC03D0000807F75030F57C0909090909090909090

I tested the patch manually, with the method described above, and automatically, letting the bots play on their own for almost 24 hours, and it seems to work fine. Without the patch the game crashes almost instantly when tested manually, and within a few hours when letting the bots play alone.

At assembly level, the patch makes the following changes:

69E65095 | F3:0F1008                | movss xmm1,dword ptr ds:[eax]           |
69E65099 | F3:0F1040 04             | movss xmm0,dword ptr ds:[eax+4]         |
69E6509E | F3:0F5C4424 10           | subss xmm0,dword ptr ss:[esp+10]        |
69E650A4 | F3:0F5C4C24 0C           | subss xmm1,dword ptr ss:[esp+C]         |
69E650AA | F3:0F59C0                | mulss xmm0,xmm0                         |
69E650AE | F3:0F59C9                | mulss xmm1,xmm1                         |
69E650B2 | F3:0F58C1                | addss xmm0,xmm1                         |
69E650B6 | 0F57C9                   | xorps xmm1,xmm1                         |
69E650B9 | 0F5AC0                   | cvtps2pd xmm0,xmm0                      |
69E650BC | 66:0F2EC8                | ucomisd xmm1,xmm0                       |
69E650C0 | 77 06                    | ja mp.orig.69E650C8                     |
69E650C2 | F2:0F51C0                | sqrtsd xmm0,xmm0                        |
69E650C6 | EB 05                    | jmp mp.orig.69E650CD                    |
69E650C8 | E8 F2740700              | call <JMP.&_libm_sse2_sqrt_precise>     |
69E650CD | F2:0F5AC0                | cvtsd2ss xmm0,xmm0                      |
69E650D1 | 0F2F05 24EDED69          | comiss xmm0,dword ptr ds:[69EDED24]     |
69E650D8 | 0F87 BEF7FFFF            | ja mp.orig.69E6489C                     |
69E65095 | F3:0F1008                | movss xmm1,dword ptr ds:[eax]           |
69E65099 | F3:0F1040 04             | movss xmm0,dword ptr ds:[eax+4]         |
69E6509E | F3:0F5C4424 10           | subss xmm0,dword ptr ss:[esp+10]        |
69E650A4 | F3:0F5C4C24 0C           | subss xmm1,dword ptr ss:[esp+C]         |
69E650AA | F3:0F59C0                | mulss xmm0,xmm0                         |
69E650AE | F3:0F59C9                | mulss xmm1,xmm1                         |
69E650B2 | F3:0F58C1                | addss xmm0,xmm1                         |
69E650B6 | F3:0F51C0                | sqrtss xmm0,xmm0                        |
69E650BA | 66:0F7EC0                | movd eax,xmm0                           |
69E650BE | 3D 0000807F              | cmp eax,7F800000                        |
69E650C3 | 75 03                    | jne mp.patch.69E650C8                   |
69E650C5 | 0F57C0                   | xorps xmm0,xmm0                         |
69E650C8 | 90                       | nop                                     |
69E650C9 | 90                       | nop                                     |
69E650CA | 90                       | nop                                     |
69E650CB | 90                       | nop                                     |
69E650CC | 90                       | nop                                     |
69E650CD | 90                       | nop                                     |
69E650CE | 90                       | nop                                     |
69E650CF | 90                       | nop                                     |
69E650D0 | 90                       | nop                                     |
69E650D1 | 0F2F05 24EDED69          | comiss xmm0,dword ptr ds:[69EDED24]     |
69E650D8 | 0F87 BEF7FFFF            | ja mp.patch.69E6489C                    |

I hope this is useful to someone.

davidmorom avatar Jul 03 '25 10:07 davidmorom

A similar patch for the Linux version "dlls/cs.so". In this case it is a bit more complex, cause when the function gets stuck on the loop, the magnitude of the vector is different each time, not infinite. So, to determine that the loop is stuck, I implemented a counter, if it gets to 100, the loop is interrupted.

To store the value of the counter, I used address [esp+0x20] on the function's stack frame. Using Ghidra I determined that this address is allocated by the compiler but never used (why? who knows, compiler things).

The file needs to be patched at two places. The first one overwrites some useless code with the initialization of the counter, before the loop. The second one replaces more useless code with the update of the counter and the comparison, at the end of the loop, after the magnitude of the vector has been calculated but before it is compared to 1.0f.

Find: DBE80F8AFA03
Replace with: C74424206400

Find: DBE80F8AF5000000DDD9
Replace with: DDD9836C242001720F90

davidmorom avatar Jul 06 '25 18:07 davidmorom