Check ScriptClassDesc_t of squirrel instance for native member function call

This enhances the ScriptFuncDescriptor_t to record the ScriptClassDesc_t
of the class for which it gets invoked.
The ScriptClassDesc_t are traversed in the function_stub() for native
function calls for member functions, to ensure the passed in instance
has a compatible type.
This prevents memory errors when incorrectly invoking native member
functions from Squirrel.
This commit is contained in:
Alexander 'z33ky' Hirsch 2025-06-11 02:14:13 +02:00
parent c851fc9bfb
commit 681a75a6a7
3 changed files with 22 additions and 6 deletions

View File

@ -263,6 +263,8 @@ inline const char * ScriptFieldTypeName( int16 eType)
//---------------------------------------------------------
struct ScriptClassDesc_t;
struct ScriptFuncDescriptor_t
{
ScriptFuncDescriptor_t()
@ -270,11 +272,13 @@ struct ScriptFuncDescriptor_t
m_pszFunction = NULL;
m_ReturnType = FIELD_TYPEUNKNOWN;
m_pszDescription = NULL;
m_pScriptClassDesc = NULL;
}
const char *m_pszScriptName;
const char *m_pszFunction;
const char *m_pszDescription;
ScriptClassDesc_t *m_pScriptClassDesc;
ScriptDataType_t m_ReturnType;
CUtlVector<ScriptDataType_t> m_Parameters;
};

View File

@ -61,7 +61,7 @@ FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_TYPE_DEDUCER );
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNC_TYPE_DEDUCER );
#define ScriptInitMemberFuncDescriptor_( pDesc, class, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, (class *)(0), &class::func ); }
#define ScriptInitMemberFuncDescriptor_( pDesc, class, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, (class *)(0), &class::func ); (pDesc)->m_pScriptClassDesc = GetScriptDesc<class>(nullptr); }
#define ScriptInitFuncDescriptorNamed( pDesc, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, &func ); }
#define ScriptInitFuncDescriptor( pDesc, func ) ScriptInitFuncDescriptorNamed( pDesc, func, #func )

View File

@ -1427,18 +1427,30 @@ SQInteger function_stub(HSQUIRRELVM vm)
if (pFunc->m_flags & SF_MEMBER_FUNC)
{
SQUserPointer self;
if (SQ_FAILED(sq_getinstanceup(vm, 1, &self, 0)))
ClassInstanceData* classInstanceData;
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
{
return sq_throwerror(vm, "Expected class userpointer");
return SQ_ERROR;
}
if (!self)
if (!classInstanceData)
{
return sq_throwerror(vm, "Accessed null instance");
}
instance = ((ClassInstanceData*)self)->instance;
// check that the type of self, or any basetype, matches the function description
ScriptClassDesc_t *selfType = classInstanceData->desc;
while (selfType != pFunc->m_desc.m_pScriptClassDesc)
{
if (!selfType)
{
return sq_throwerror(vm, "Mismatched instance type");
}
selfType = selfType->m_pBaseDesc;
Assert(selfType != classInstanceData->desc); // there should be no infinite loop
}
instance = classInstanceData->instance;
}
ScriptVariant_t script_retval;