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

All other Source.Python topics and issues.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Mon Apr 18, 2016 10:39 pm

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.
Last edited by iPlayer on Sun Oct 16, 2016 2:43 pm, edited 1 time in total.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

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

Postby L'In20Cible » Tue Apr 19, 2016 12:45 am

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.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Tue Apr 19, 2016 1:42 am

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?
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

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

Postby L'In20Cible » Tue Apr 19, 2016 2:30 am

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.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Tue Apr 19, 2016 2:43 am

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.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Tue Apr 19, 2016 3:07 am

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.
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

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

Postby satoon101 » Tue Apr 19, 2016 2:22 pm

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)
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Tue Apr 19, 2016 2:37 pm

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.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Tue Apr 19, 2016 4:55 pm

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.
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

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

Postby Ayuto » Tue Apr 19, 2016 7:54 pm

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?
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Tue Apr 19, 2016 7:59 pm

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
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

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

Postby Ayuto » Tue Apr 19, 2016 8:02 pm

Okay thanks! I will take a look at it tomorrow. :)
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Tue Apr 19, 2016 8:07 pm

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?
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

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

Postby Ayuto » Wed Apr 20, 2016 8:12 pm

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. :(
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

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

Postby iPlayer » Wed Apr 20, 2016 8:36 pm

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?
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

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

Postby satoon101 » Wed Apr 20, 2016 8:51 pm

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
User avatar
Ayuto
Project Leader
Posts: 2193
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

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

Postby Ayuto » Sat Feb 06, 2021 2:49 pm

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

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 2 guests