Archive for the ‘Bug Fixes’ Category

Minor SourceHook changes

Thursday, February 10th, 2005

Yesterday we experienced a weird crash in SourceHook on server unload. After a lot of debugging, I have found that a part of SourceMod was calling GameEventManager->RemoveListener _after_ SourceHook has been shut down. Of course, parts of SourceMod should be calling interfaces through the CallClass, but it still has no reason to crash. The problem was that the vtable of the interface was not reset. So when the function got called, SourceHook was searching for the entry in the hooked interfaces list, it found nothing (because the interface had already been removed from CSourceHook::Shutdown), and tried to access it, so the server crashed. So I decided to add a check whether something has been found to SH_FIND_ENTRY. But what should it do if it hasn’t? It can’t call the original function, because the original vtable entry is not available. So I decided to shut down the server with a proper message. Still better than a crash.

Anyway, why is it possible to remove an interface from the list without reseting its vtable? When I was first testing SourceHook, it crashed when reseting the vtable on unload. I assumed that the pointers were already invalid, so I just made reseting the vtable optional. Later, DS found out that the pointers were available, but the vtables were reprotected (because VirtualProtect/mprotect affects the whole page, not only the range you pass). So now, we reset the vtables on unload, but do not reprotect them.

I have changed the SH_REMOVEINTERFACE macro a bit; it doesn’t take the “reset” parameter; instead, it always resets the vtable. If you are _sure_ that the pointer is invalid, you can still use the SH_REMOVEINTERFACE_NORESET macro. Note that if you use this on an interface that is still valid, and the interface is used later, the server will crash. This should prevent people from accidentally not reseting the vtable.