alliedmodders / sourcemod

SourceMod - Source Engine Scripting and Administration
http://www.sourcemod.net/
974 stars 421 forks source link

FreeEvent call in EventManager::OnFireEvent breaks event pointer #1685

Open Alexeyt89 opened 2 years ago

Alexeyt89 commented 2 years ago

Help us help you

Environment

Description

If an event in a plugin is prehooked and blocked with Plugin_Handled the event is deleted in EventManager::OnFireEvent -> FreeEvent. So all the other hooks of IGameEventManager2::FireEvent receive dead IGameEvent pointer.

gameevents->FreeEvent(info.pEvent) should be removed from EventManager::OnFireEvent and EventManager::OnFireEvent_Post to fix this problem.

asherkin commented 2 years ago

https://bugs.alliedmods.net/show_bug.cgi?id=5097 has the history here and a lot of discussion around the various options, unfortunately leaking memory is not a great option.

Alexeyt89 commented 2 years ago

If I understand right and the idea here is to prevent event transmitting when Plugin_Handled is returned then instead of deleting the event it can be made "local". There is a check in CGameEventTransmitter::TransmitGameEvent which prevents transmitting of local events. The IsLocal() function can be hooked and the return value can be changed to true. As events always get deleted at the end of CGameEventManager::FireEventIntern, it should be safe. Another way would be to add an interface for extensions so that developers wouldn't need to hook the FireEvent function.

psychonic commented 2 years ago

Just blocking transmission of the event wouldn't cover all use cases, since listeners in the server itself would still receive it.

dvander commented 2 years ago

Can we reference count the in-flight object?

dvander commented 2 years ago

Or, wait until all notifications are fired and then free.

Alexeyt89 commented 2 years ago

Just blocking transmission of the event wouldn't cover all use cases, since listeners in the server itself would still receive it.

What if hook and block all IGameEventListener::FireGameEvent calls for such events?