Page 1 of 1

CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Mon Apr 18, 2016 10:39 pm
by iPlayer
Hi there guys

So the issue I've run into is not present on Windows CS:S, only on Linux SRCDS.

The following code

Syntax: Select all

from entities.entity import Entity
from entities.hooks import EntityCondition, EntityPreHook
from events import Event
from memory import make_object
from players.entity import Player
from players.helpers import index_from_userid

from mathlib import NULL_VECTOR


def strip(player):
for index in player.weapon_indexes():
weapon = Entity(index)
print("Dropping {}".format(weapon.classname))
player.drop_weapon(weapon.pointer, NULL_VECTOR, NULL_VECTOR)
print("Dropped successfully.")
weapon.remove()


@Event('player_jump')
def on_player_jump(game_event):
player = Player(index_from_userid(game_event['userid']))
strip(player)


@EntityPreHook(EntityCondition.is_player, 'on_take_damage')
def on_take_damage(args):
player = make_object(Player, args[0])
strip(player)


should strip player's weapons in 2 cases:
a. They jump (just to prove that stripping weapons works)
b. They take damage

So stripping the weapons during jumping event works fine.
Stripping the weapons in on_take_damage pre-hook works fine too, but only on Windows. On Linux it crashes between those two print statements. And it's not getting weapon's pointer, I checked that too, it specifically crashes on drop_weapon.

What I'm trying to do though is a pretty simple thing - I need to strip player's weapons on their death, and I'm the reason they die - I set TakeDamageInfo's damage attribute higher than their health. And I'm dead set against using events instead of OnTakeDamage hook because I may need to cancel the function from executing.

If there's no way this thing won't crash on Linux, I guess I'll need to save player's weapons indexes before they die, then catch player_death and remove these weapons by the saved indexes.

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 12:45 am
by L'In20Cible
Use a post hook, instead. If you use a pre-hook and doesn't block the original function call, the call pass a no longer valid (as you force dropped it) pointer for the weapon used.

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 1:42 am
by iPlayer
Ehm... But will I be able to prevent function from executing and/or able to change TakeDamageInfo attributes with PostHook?
And I don't quite understand what you mean by "call passes a no longer valid pointer because I force dropped it", could you clarify a bit?
And why this is OS-dependent?

PS Something's wrong with your Location field after this whole phpBB migration, L'In20Cible

EDIT: Wait, I guess I understand a bit... Does the drop_weapon function get called with a wrong stack? Anyways, why is it OS-dependent?

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 2:30 am
by L'In20Cible
To be honnest, I think I would rather use a different solution. What if you post-hook "drop_weapon" and check the player dead state, if the player is dead, you remove the weapon otherwise you pass? It all depends if the server is setting that flag prior or after dropping the weapons upon player death, tho.

Yes, I've noticed for my location. Seems to be stripped after the "é" so most likely an encoding problem during the conversion.

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 2:43 am
by iPlayer
Thanks for the idea, I didn't think drop_weapon would fire on player death.

I don't even need to check the dead state. These weapons still should be removed no matter if the player is dead or just about to die. In my case they can't drop weapons by pressing G, too. That simplifies the case.

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 3:07 am
by iPlayer
Weird... I can't get Player instance inside of drop_weapon post-hook.

Code: Select all

@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
def on_drop_weapon(args, ret_val):
    player = make_object(Player, args[0])
crashses

Code: Select all

@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
def on_drop_weapon(args, ret_val):
    player = Player(index_from_pointer(args[0]))
crashes too. Crashes on index_from_pointer call.

CS:S, Windows.

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 2:22 pm
by satoon101
You can try storing the index via the pointer's address in a dictionary with a PreHook, so that you can access it on a PostHook:

Code: Select all

drop_indexes = dict()

@EntityPreHook(EntityCondition.is_player, 'drop_weapon')
def pre_drop_weapon(args):
    drop_indexes[args[0].address] = index_from_pointer(args[0])

@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
def post_drop_weapon(args):
    player = drop_indexes.pop(args[0].address)

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 2:37 pm
by iPlayer
That resulted in KeyError on drop_indexes.pop because pointer addresses were different.

Code: Select all

from core import echo_console
from entities.hooks import EntityCondition, EntityPostHook, EntityPreHook


@EntityPreHook(EntityCondition.is_player, 'drop_weapon')
def pre_drop_weapon(args):
    echo_console("PreHook pointer address: {}".format(args[0].address))


@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
def post_drop_weapon(args, ret_val):
    echo_console("PostHook pointer address: {}".format(args[0].address))


Regular drop:
PreHook pointer address: 875258832
PostHook pointer address: 1497103


Drop due to player's death:
PreHook pointer address: 875258832
PostHook pointer address: 0


EDIT: Null-pointer happens when dropping weapon_knife, to be certain.

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 4:55 pm
by iPlayer
Probably will go with this

If there's no way this thing won't crash on Linux, I guess I'll need to save player's weapons indexes before they die, then catch player_death and remove these weapons by the saved indexes.


I believe I even know these indexes from the beginning, because these weapons are spawned by me.

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 7:54 pm
by Ayuto
iPlayer wrote:Anyways, why is it OS-dependent?

Hooking/calling functions is highly OS dependent!

But I'm a bit confused now. Which code is causing crashes? Code to reproduce the issue would be nice or is the code in your first post already causing crashes?

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 7:59 pm
by iPlayer
Yes, code from the first post causes crash on Linux CS:S, but on Windows runs just fine.
Both pieces of code from post 7514 cause crashes on Windows CS:S, I don't know about Linux - not tested.

Note that I run listen server on Windows and SRCDS on Linux

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 8:02 pm
by Ayuto
Okay thanks! I will take a look at it tomorrow. :)

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Tue Apr 19, 2016 8:07 pm
by iPlayer
Thanks. I should've mentioned that those 2 crashes are unrelated to each other, should've probably posted the second in a separate thread. I just discovered the second one while trying to work the first one around.

The code from the first post crashes if I call drop_weapon from inside a pre-hook

The second pieces of code crash if I try to retrieve Player instance from inside a post-hook of drop_weapon. After a bit of research it occurs that post-hook of that function provides invalid pointers in args[0] while pre-hook works fine. Maybe drop_weapon changes that pointer to something else during execution?

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Wed Apr 20, 2016 8:12 pm
by Ayuto
iPlayer wrote:Weird... I can't get Player instance inside of drop_weapon post-hook.

Syntax: Select all

@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
def on_drop_weapon(args, ret_val):
player = make_object(Player, args[0])
crashses

Syntax: Select all

@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
def on_drop_weapon(args, ret_val):
player = Player(index_from_pointer(args[0]))
crashes too. Crashes on index_from_pointer call.

CS:S, Windows.

This one is quite easy to explain. drop_weapon's calling convention is THISCALL and on Windows the "this" pointer (the player) is passed to the function through the ECX register. In a pre-hook this register contains a valid "this" pointer, because it just has been passed and we are accessing it before the original function is even able to access it. However, during the execution of the original function it can happen that it assigns a new value to the ECX register (e.g. for internal calculations). Thus, the post-hook receives the value that has been assigned during the execution of the original function. This value is not a valid "this" pointer (player pointer) anymore, so index_from_pointer() crashes. You can work around that just like Satoon mentioned. You only need an identifier that persists in a pre-hook and post-hook.

Syntax: Select all

from entities.hooks import EntityCondition
from entities.hooks import EntityPostHook
from entities.hooks import EntityPreHook

import memory

from players.entity import Player

ecx_storage = {}

@EntityPreHook(EntityCondition.is_player, 'drop_weapon')
def pre_on_drop_weapon(args):
player = memory.make_object(Player, args[0])
ecx_storage[args.registers.esp.address.address] = player

@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
def post_on_drop_weapon(args, ret_val):
player = ecx_storage.pop(args.registers.esp.address.address)
print('Player {} dropped a weapon.'.format(player.name))

The code that crashes on Windows should work fine on Linux, because all arguments are pushed onto the stack (ESP register). But this isn't always true! It can also happen that the original function assigns a new value to an argument on the stack, but I think that's quite rare.

Regarding the issue in your first post:
I guess I will need some more time to figure out what's wrong. I don't have a clue at the moment, sorry. :(

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Wed Apr 20, 2016 8:36 pm
by iPlayer
Thank you for the explanation, Ayuto, it's some useful stuff to read. I get the point. I thought that the player pointer is stored in the stack and function changes the stack, but it turned out the pointer is stored in ECX register and the function changes this register.

And regarding to the first issue - well, just keep in mind that I can bypass that issue by using different approaches, so if it turns out that I went against something serious (e.g. did something illogical) with that first code, maybe it's not worth to fix it.
I might also mention that I've experienced something similar when trying to call functions from inside a pre-event, and I guess PreEvent-s use PreHook-s too?

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Wed Apr 20, 2016 8:51 pm
by satoon101
iPlayer wrote:I might also mention that I've experienced something similar when trying to call functions from inside a pre-event, and I guess PreEvent-s use PreHook-s too?

Yes, PreEvents are run using a PreHook of game_event_manager.fire_event:
https://github.com/Source-Python-Dev-Team/Source.Python/blob/master/addons/source-python/packages/source-python/events/hooks.py#L193

Re: CS:S Linux crash when dropping weapon in OnTakeDamage pre-hook

Posted: Sat Feb 06, 2021 2:49 pm
by Ayuto
Just in case someone stumbles about this thread: the workaround with the ecx_storage is not required anymore. You can now use this instead:
http://wiki.sourcepython.com/developing ... _registers