alliedmodders / amxmodx

AMX Mod X - Half-Life 1 Scripting and Administration
http://www.amxmodx.org/
499 stars 203 forks source link

[TFC] [Linux] Crash shortly after infecting #988

Closed pizzahut2 closed 3 years ago

pizzahut2 commented 3 years ago

0 0xf1c0a4a3 in Client_Damage(void*) () from tfc/addons/amxmodx/modules/tfcx_amxx_i386.so

Assuming it's this: https://github.com/alliedmodders/amxmodx/blob/db9421d0bec3a5390fb716fa265969767ae7843c/modules/tfcx/usermsg.cpp#L190

Happens on Linux HLDS with AMXX 1.9 and 1.10. Windows seems to be fine.

No old "tfc_i386.so" lying around this time which is accidentally loaded instead of "tfc.so".

AMXX v1.8.3 build 4706, which is the version before the last infection patch (28 Mar 2015), runs stable on the Linux HLDS, but this AMXX version crashes on Windows instead (shortly after infecting an enemy).

I thought it's another Linux offset related issue, but PD_TIMER_OWNER doesn't seem to return the expected value. When reading the value of this pdata, it should return the ID of the medic who was infecting, which is different from "entity_get_edict(ent, EV_ENT_owner)" as the latter just gives the ID of the infected player. Instead, I get 0 when reading the raw integer value, or -1 when using "get_pdata_ent" (an error meaning "empty entity").

Clean HLDS install on Linux with these versions:

version Protocol version 48 Exe version 1.1.2.2/Stdio (tfc) Exe build: 19:52:19 Aug 3 2020 (8684)

meta version Metamod v1.21p-APG 2021/08/13 (5:13) Patch: Metamod-P (mm-p) v40

amxx version AMX Mod X 1.10.0.5437 (http://www.amxmodx.org)

foxbot "foxbot" is "0.800-beta3"

tfc_pdata_test.sma v3 2021-09-11 This doesn't find anything:

          for (offset = PD_TIMER_OWNER*0; offset <= PD_TIMER_OWNER*8; offset++)
          {
            timer_owner = get_pdata_ehandle(ent, offset)
            if (timer_owner == id)
              console_print(id, "%d", timer_owner)
          }
pizzahut2 commented 3 years ago

I think it's fixed (worked around) in this fork by removing the code which is causing the infection crash ("rogue code").

https://github.com/APGRoboCop/amxmodx/blob/master/modules/tfcx/usermsg.cpp#L216

Edit: I had problems with the configs dir from this fork. I replaced it with the configs dir from official AMXX and the fork worked fine then.

ShootingKing-AM commented 3 years ago

I think it's fixed (worked around) in this fork by removing the code which is causing the infection crash ("rogue code").

https://github.com/APGRoboCop/amxmodx/blob/master/modules/tfcx/usermsg.cpp#L216

Edit: I had problems with the configs dir from this fork. I replaced it with the configs dir from official AMXX and the fork worked fine then.

But don't you think if you use this workaround, the TFC stats will not be accurate, if you disable those lines saveshot is being called on a rougue pAttacker.

Anyways, I wanted to know something, how do you get infection causer playerID? Have you already tried to Register TakeDmg or register DmgUserMsg and dump some of the inflector ent data(classname, owner(owner's Id, owner's classname, owner's owner), Id)? (via plugin)

ShootingKing-AM commented 3 years ago

TL;DR

Tfcx is not using the correct method to get the InfectOR playerID. PR-70 #991 fixes the method.

Ok it seems pizza is busy. I can again confirm that newest amxmodx build on Linux(tfc mod) crashes.

So when a player is Infected, a timer is spawned and its Owner is the InfectED player, its Enemy is the InfectOR. So we dont need to do any hardcoding with pdatas, just get the timer->enemy to get the (infectOR or)Attacker (to save his stats). After some ent data dumps from tfcx module (lines - 124-129 and 160-165, its been confirmed that timer->enemy is the infectOR1,2.

Reference1:

L 09/13/2021 - 19:28:58: "Shooting King::d( ^ _ ^ )b<1><STEAM_0:xxx><Red>" triggered "Medic_Infection" against "[FoX]Stimpy<2><BOT><Blue>"
L 09/13/2021 - 19:28:58: Clinet_damage Called with state-3 dmg-4 [FoX]Stimpy(class:player) 0
L 09/13/2021 - 19:28:58:    Called with enemy-0 Shooting King::d( ^ _ ^ )b(class:player)
L 09/13/2021 - 19:28:58:    attacker is player and his active weapon(`TFC_WPN_MEDIKIT`) FL_CLIENT | FL_FAKECLIENT

...after 2 secs...

L 09/13/2021 - 19:29:00: Clinet_damage Called with state-3 dmg-8 [FoX]Stimpy(class:player) 0
L 09/13/2021 - 19:29:00:    Called with enemy-0 (class:timer)
L 09/13/2021 - 19:29:00:    attacker is 'timer'(with its enemy as Shooting King::d( ^ _ ^ )b[Class:player]) and his owner is '[FoX]Stimpy(class:player)' enemy->owner has flags - (FL_CLIENT | FL_FAKECLIENT)

Reference2: tfc.so :: CTFMedikit::AxeHit(CBaseEntity *,Vector,TraceResult *) spawns a New Timer (CBaseEntity * child) with entvar->Owner and entvar->Enemy.

tfc.so@.text:001572F7

Also as i before guessed, this Patch-(https://github.com/APGRoboCop/amxmodx/commit/dd45a13b616959b0e7cdd71ec75fee8284983ac3) will not work since, the timer->owner is NOT the attacker but the infected player(victim). So when a player is infected, that patch will count the shot/damage into the victim's(infected player) account stats as if the victim has shot someone.

And coming to pdata offsets,

#if defined(_WIN32)
    #define LINUXOFFSET         0
    #define PLAYER_LINUXOFFSET  0
    #define CLIP_LINUXOFFSET    0
#else
    #define LINUXOFFSET         4
    #define PLAYER_LINUXOFFSET  5
    #define CLIP_LINUXOFFSET    4
#endif

#define PD_TIMER_OWNER      932 + PLAYER_LINUXOFFSET // 937 on Linux

The pdata offsets 937*4 (of CBasePlayer) on linux does not refer to any relavant data. pDatas arround that offset are,

CBasePlayer
{
...
    float                      m_flLastTalkTime;     /*  3708     4 */
    int                        m_cSpamPoints;        /*  3712     4 */
    float                      m_flNextSBarUpdateTime; /*  3716     4 */
    int                        m_izSBarState[7];     /*  3720    28 */
    float                      m_flStatusBarDisappearDelay; /*  3748     4 */ <------937*4
    class EHANDLE             m_hLastIDTarget;       /*  3752     8 */
    BOOL                       m_bUpdatedCommandMenu; /*  3760     4 */
    int                        m_iClientIsFeigning;  /*  3764     4 */
    int                        m_iClientIsDetpacking; /*  3768     4 */
    int                        m_iClientDetpackAmmo; /*  3772     4 */
...
}

Even from GameData, it dosent refer to anything relavant. Also there is no pData member named TIMER_OWNER in whole CBasePlayer inheritance. The crash line is L93 - which is obvious because the offset dosent really point to any edict_t * object in mem.

PR Fixes this by simply taking Attacker edict_t from the Timer-Ent->entvars->enemy, which is the correct way as can been seen in tfc.so using the same - for -dev logging the below line,

L 09/13/2021 - 19:28:58: "Shooting King::d( ^ _ ^ )b<1><STEAM_0:xxx><Red>" triggered "Medic_Infection" against "[FoX]Stimpy<2><BOT><Blue>"

Testing and offsets checked on with Latest Amxmodx v1.10 (Build#5437), Linux HLDS (on Ubuntu 20.04.1 LTS (Focal Fossa)),

Protocol version 48 Exe version 1.1.2.2/Stdio (tfc) Exe build: 19:52:19 Aug 3 2020 (8684))

Windows HLDS

Protocol version 48 Exe version 1.1.2.2 (tfc) Exe build: 19:52:53 Aug 3 2020 (8684)

debug binaries: has much log_to_server_console in Client_dmg(). bins.zip

pizzahut2 commented 3 years ago

Tested the release binaries on Linux and Windows, they seem to work fine. Could this patch be applied to AMXX 1.9 as well, since this version is still supported?

ShootingKing-AM commented 3 years ago

@Arkshine