Raised This Month: $7 Target: $400
 1% 

CSGO correct usage of manual hooks


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
kadet.89
Veteran Member
Join Date: Nov 2012
Location: Serbia
Old 12-21-2020 , 09:22   CSGO correct usage of manual hooks
Reply With Quote #1

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.
kadet.89 is offline
Send a message via Skype™ to kadet.89
asherkin
SourceMod Developer
Join Date: Aug 2009
Location: OnGameFrame()
Old 12-22-2020 , 07:41   Re: CSGO correct usage of manual hooks
Reply With Quote #2

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.
__________________
asherkin is offline
kadet.89
Veteran Member
Join Date: Nov 2012
Location: Serbia
Old 06-09-2021 , 15:14   Re: CSGO correct usage of manual hooks
Reply With Quote #3

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);

Attached Files
File Type: txt c8d2726a-2747-4629-70deed8c-87b17e27.dmp.txt (116.1 KB, 145 views)

Last edited by kadet.89; 06-10-2021 at 11:15.
kadet.89 is offline
Send a message via Skype™ to kadet.89
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 07:15.


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