Fix scriptanimevent_t::SetOption()

The string argument refers to memory managed by the Squirrel VM. It has
no guarantee that the string will continue to exist after the hook, from
which this can be called, has finished executing.
To fix this, allocate memory to copy the string into and manage it as
needed.
This commit is contained in:
Alexander 'z33ky' Hirsch 2024-11-19 13:17:48 +01:00
parent 8e8bdfc371
commit 7d78384b26
5 changed files with 57 additions and 23 deletions

View File

@ -16,6 +16,10 @@
#include "saverestore_utlvector.h"
#include "dt_utlvector_send.h"
#ifdef MAPBASE_VSCRIPT
#include "mapbase/vscript_funcs_shared.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -471,7 +475,8 @@ void CAnimationLayer::DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAni
}
#ifdef MAPBASE_VSCRIPT
if (eventHandler->m_ScriptScope.IsInitialized() && eventHandler->ScriptHookHandleAnimEvent( &event ) == false)
scriptanimevent_t wrapper( event );
if (eventHandler->m_ScriptScope.IsInitialized() && !eventHandler->ScriptHookHandleAnimEvent( wrapper ))
continue;
#endif

View File

@ -1261,7 +1261,8 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler )
}
#ifdef MAPBASE_VSCRIPT
if (eventHandler->ScriptHookHandleAnimEvent( &event ) == false)
scriptanimevent_t wrapper( event );
if (!eventHandler->ScriptHookHandleAnimEvent( wrapper ))
continue;
#endif
@ -1299,11 +1300,11 @@ void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseAnimating::ScriptHookHandleAnimEvent( animevent_t *pEvent )
bool CBaseAnimating::ScriptHookHandleAnimEvent( scriptanimevent_t &event )
{
if (m_ScriptScope.IsInitialized() && g_Hook_HandleAnimEvent.CanRunInScope(m_ScriptScope))
{
HSCRIPT hEvent = g_pScriptVM->RegisterInstance( reinterpret_cast<scriptanimevent_t*>(pEvent) );
HSCRIPT hEvent = g_pScriptVM->RegisterInstance( &event );
// event
ScriptVariant_t args[] = { hEvent };

View File

@ -16,6 +16,9 @@
#include "datacache/idatacache.h"
#include "tier0/threadtools.h"
#ifdef MAPBASE_VSCRIPT
struct scriptanimevent_t;
#endif
struct animevent_t;
struct matrix3x4_t;
@ -146,7 +149,7 @@ public:
virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); // Handle events that have happend since last time called up until X seconds into the future
virtual void HandleAnimEvent( animevent_t *pEvent );
#ifdef MAPBASE_VSCRIPT
bool ScriptHookHandleAnimEvent( animevent_t *pEvent );
bool ScriptHookHandleAnimEvent( scriptanimevent_t &event );
#endif
int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName );

View File

@ -535,7 +535,7 @@ bool CAnimEventTInstanceHelper::Get( void *p, const char *pszKey, ScriptVariant_
{
DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey );
animevent_t *ani = ((animevent_t *)p);
animevent_t *ani = &((scriptanimevent_t *)p)->event;
if (FStrEq( pszKey, "event" ))
variant = ani->event;
else if (FStrEq( pszKey, "options" ))
@ -558,13 +558,21 @@ bool CAnimEventTInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_
{
DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey );
animevent_t *ani = ((animevent_t *)p);
scriptanimevent_t *script_ani = ((scriptanimevent_t *)p);
animevent_t *ani = &script_ani->event;
if (FStrEq( pszKey, "event" ))
{
return variant.AssignTo( &ani->event );
}
else if (FStrEq( pszKey, "options" ))
// broken: return variant.AssignTo( &ani->options );
// variant memory is freed afterwards
return false;
{
char *szOptions;
if (!variant.AssignTo( &szOptions ))
{
return false;
}
script_ani->SetOptions( szOptions );
}
else if (FStrEq( pszKey, "cycle" ))
return variant.AssignTo( &ani->cycle );
else if (FStrEq( pszKey, "eventtime" ))

View File

@ -172,30 +172,47 @@ private:
//-----------------------------------------------------------------------------
// Exposes animevent_t to VScript
//-----------------------------------------------------------------------------
struct scriptanimevent_t : public animevent_t
struct scriptanimevent_t
{
int GetEvent() { return event; }
void SetEvent( int nEvent ) { event = nEvent; }
friend class CAnimEventTInstanceHelper;
const char *GetOptions() { return options; }
void SetOptions( const char *pOptions ) { options = pOptions; }
public:
scriptanimevent_t( animevent_t &event ) : event( event ), options( NULL ) { }
~scriptanimevent_t( ) { delete[] options; }
float GetCycle() { return cycle; }
void SetCycle( float flCycle ) { cycle = flCycle; }
int GetEvent() { return event.event; }
void SetEvent( int nEvent ) { event.event = nEvent; }
float GetEventTime() { return eventtime; }
void SetEventTime( float flEventTime ) { eventtime = flEventTime; }
const char *GetOptions() { return event.options; }
void SetOptions( const char *pOptions )
{
size_t len = strlen( pOptions );
delete[] options;
event.options = options = new char[len + 1];
memcpy( options, pOptions, len + 1 );
}
int GetType() { return type; }
void SetType( int nType ) { eventtime = type; }
float GetCycle() { return event.cycle; }
void SetCycle( float flCycle ) { event.cycle = flCycle; }
HSCRIPT GetSource() { return ToHScript( pSource ); }
float GetEventTime() { return event.eventtime; }
void SetEventTime( float flEventTime ) { event.eventtime = flEventTime; }
int GetType() { return event.type; }
void SetType( int nType ) { event.type = nType; }
HSCRIPT GetSource() { return ToHScript( event.pSource ); }
void SetSource( HSCRIPT hSource )
{
CBaseEntity *pEnt = ToEnt( hSource );
if (pEnt)
pSource = pEnt->GetBaseAnimating();
event.pSource = pEnt->GetBaseAnimating();
}
private:
animevent_t &event;
// storage for ScriptVariant_t string, which may be temporary
char *options;
};
class CAnimEventTInstanceHelper : public IScriptInstanceHelper