AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Coding MM:S Plugins & SM Extensions (https://forums.alliedmods.net/forumdisplay.php?f=75)
-   -   CSGO correct usage of manual hooks (https://forums.alliedmods.net/showthread.php?t=329377)

kadet.89 12-21-2020 09:22

CSGO correct usage of manual hooks
 
I have a manual hook in my extension declared this way:

PHP Code:

SH_DECL_MANUALHOOK2_void(CPlayer_PlayerRunCmd000CUserCmd*, void*)

CPlayer::CPlayer(CBaseEntityentity)
{
    
SH_ADD_MANUALHOOK(CPlayer_PlayerRunCmdGetBaseEntity(), SH_MEMBER(this, &CPlayer::OnPlayerRunCmd), false);
}

CPlayer::~CPlayer(void)
{
    
SH_REMOVE_MANUALHOOK(CPlayer_PlayerRunCmdGetBaseEntity(), SH_MEMBER(this, &CPlayer::OnPlayerRunCmd), false);
}

void CPlayer::OnPlayerRunCmd(CUserCmd *cmdvoid *moveHelper)
{
    const 
int pressedButtons GetButtonPressed();
    if(
pressedButtons IN_RELOAD)
    {
        
CBaseEntityactiveWeapon GetActiveWeaponPointer();
        if(!
activeWeapon || strcmp(activeWeapon->GetClassName(), "weapon_knife") != 0)
            
RETURN_META(MRES_IGNORED);

        
CBaseEntityak47 GetWeaponByClassname("weapon_ak47");
        if(!
ak47)
            
RETURN_META(MRES_IGNORED);

        
SH_MCALL(GetBaseEntity(), CPlayer_Weapon_Switch)(ak470);
    }

    
RETURN_META(MRES_IGNORED);


This works, but quite often crashes the server. On in the crashstack I always see the same funtion name and the same stack:

PHP Code:

 0  server.so 0x5d5463
 1  server
.so 0x760f0b
 2  server
.so 0x767b7a
 3  server
.so 0xb8f9e7
 4  sdkhooks
.ext.2.csgo.so 0x1bdfe
 5  server
.so 0x77c1d3
 6  server
.so 0x77c951
 7  server
.so 0x75f47c
 8  server
.so 0xb8c335
 9  extension18
.ext.2.csgo.so 0x35f91
10  server
.so 0x777a94
11  server
.so 0x734db5 

The function where crash begins (extension18.ext.2.csgo.so + 0x35f91) Scroll to the comment (// Crashes here)

PHP Code:

int __cdecl __SourceHook_MFHCls_CPlayer_PlayerRunCmd::Func(int a1int a2int a3)
{
  
int v3// eax@1
  
int v4// ebx@1
  
int (__cdecl *v5)(intintint); // edx@2
  
int v6// eax@3
  
int (__cdecl *v7)(intintint); // edx@10
  
int v8// eax@11
  
int v10// [sp+8h] [bp-28h]@1
  
int v11// [sp+Ch] [bp-24h]@1
  
int v12// [sp+10h] [bp-20h]@1
  
void (__cdecl *v13)(intintint); // [sp+14h] [bp-1Ch]@1

  
v12 0;
  
v3 = (*(int (__cdecl **)(intintintintvoid (__cdecl **)(intintint), int *, int *, int *, _DWORD_DWORD))(*(_DWORD *)g_SHPtr 76))(
         
g_SHPtr,
         
__SourceHook_MFHCls_CPlayer_PlayerRunCmd::ms_HI,
         *(
_DWORD *)(a1 + *(_DWORD *)&__SourceHook_MFHCls_CPlayer_PlayerRunCmd::ms_MFI[12])
       + 
* *(_DWORD *)&__SourceHook_MFHCls_CPlayer_PlayerRunCmd::ms_MFI[8],
         
a1,
         &
v13,
         &
v12,
         &
v11,
         &
v10,
         
0,
         
0);
  
v11 0;
  
v4 v3;
  while ( 
)
  {
    
v6 = (**(int (__cdecl ***)(_DWORD))v4)(v4);
    if ( !
v6 )
      break;
    
v10 0;
    
v5 = *(int (__cdecl **)(intintint))(*(_DWORD *)v6 8);
    if ( 
v5 == __SourceHook_MFHCls_CPlayer_PlayerRunCmd::CMyDelegateImpl::Call )
    {
      
v5 = *(int (__cdecl **)(intintint))(v6 8);
      
v6 = *(_DWORD *)(v6 4) + *(_DWORD *)(v6 12);
      if ( (
unsigned __int8)v5 )
        
v5 = *(int (__cdecl **)(intintint))((char *)v5 + *(_DWORD *)v6 1);
    }
    
v5(v6a2a3);
    
v11 v10;
    if ( 
v10 v12 )
      
v12 v10;
  }
  if ( 
v12 != && (unsigned __int8)(*(int (__cdecl **)(int))(*(_DWORD *)v4 12))(v4) )
  {
    if ( (
unsigned __int8)v13 )
      (*(
void (__cdecl **)(intintint))((char *)v13 + *(_DWORD *)a1 1))(a1a2a3);
    else
      
v13(a1a2a3); // Crashes here
  
}
  
v11 0;
  while ( 
)
  {
    
v8 = (**(int (__cdecl ***)(_DWORD))v4)(v4);
    if ( !
v8 )
      break;
    
v10 0;
    
v7 = *(int (__cdecl **)(intintint))(*(_DWORD *)v8 8);
    if ( 
v7 == __SourceHook_MFHCls_CPlayer_PlayerRunCmd::CMyDelegateImpl::Call )
    {
      
v7 = *(int (__cdecl **)(intintint))(v8 8);
      
v8 = *(_DWORD *)(v8 4) + *(_DWORD *)(v8 12);
      if ( (
unsigned __int8)v7 )
        
v7 = *(int (__cdecl **)(intintint))((char *)v7 + *(_DWORD *)v8 1);
    }
    
v7(v8a2a3);
    
v11 v10;
    if ( 
v10 v12 )
      
v12 v10;
  }
  return (*(
int (__cdecl **)(intint))(*(_DWORD *)g_SHPtr 80))(g_SHPtrv4);


Can somebody give me some advice what it could be?
There are some other hooks which I removed from the example: SetTransmit, OnTakeDamage, Weapon_Switch, Weapon_Equip. None of them crashes, but PlayerRunCmd couses crashes in all my extensions. And I don't see any difference.
I thought that it could be not removed CPlayer instance when the CBaseEntity of the attached player stops existing, but the tests show that CPlayer is always deleted before the attached entity is deleted. If I use GameFrame hook instead, then the crashes go away.

asherkin 12-22-2020 07:41

Re: CSGO correct usage of manual hooks
 
I don't think there is anything wrong with your hook, the crash is quite far down the call stack - based on the stack trace and your code, I'd say the game just isn't liking you calling Weapon_Switch at that time.

kadet.89 06-09-2021 15:14

Re: CSGO correct usage of manual hooks
 
1 Attachment(s)
I keep experiencing this crash in 5 of my extensions. I tried to dig deeper into this problem and found out that the crash only happens if an extension with either OnPlayerRunCmd or OnPostThink hooks for all players is running. For this crash to happen it is enough to have an empty hook, like this:
PHP Code:

CPlayer::CPlayer(CBaseEntityentity)
    : 
Inherited(entity)
{
    
SH_ADD_MANUALHOOK(CPlayer_PostThinkGetBaseEntity(), SH_MEMBER(this, &CPlayer::OnPostThink), true);
}

CPlayer::~CPlayer(void)
{
    
SH_REMOVE_MANUALHOOK(CPlayer_PostThinkGetBaseEntity(), SH_MEMBER(this, &CPlayer::OnPostThink), true);
}

void CPlayer::OnPostThink()
{
    
RETURN_META(MRES_IGNORED);


If I comment lines SH_ADD_MANUALHOOK and SH_REMOVE_MANUALHOOK the server stops crashing. Can it be a bug in sourcemod? If yes, then is there a way to debug it?

UPD
It turns out that Weapon_CanUse hook can also couse this crash. tripmines.ext.2.csgo.so + 0x96ebc - int __cdecl __SourceHook_MFHCls_CPlayer_Weapon_CanUse::Fu nc(int a1, int a2)

PHP Code:

CPlayer::CPlayer(CBaseEntityentity)
    : 
Inherited(entity)
{
    
SH_ADD_MANUALHOOK(CPlayer_Weapon_CanUseGetBaseEntity(), SH_MEMBER(this, &CPlayer::OnWeapon_CanUse), false);
}

CPlayer::~CPlayer(void)
{
    
SH_REMOVE_MANUALHOOK(CPlayer_Weapon_CanUseGetBaseEntity(), SH_MEMBER(this, &CPlayer::OnWeapon_CanUse), false);
}

bool CPlayer::OnWeapon_CanUse(CBaseEntitypWeapon)
{
    
RETURN_META_VALUE(MRES_IGNOREDtrue);




All times are GMT -4. The time now is 01:53.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.