Skip to content

Commit b3d5152

Browse files
authored
Merge pull request ValveSoftware#436 from z33ky/vscript-member-function-call-safety
VScript member function call safety
2 parents 834196c + c659af5 commit b3d5152

File tree

3 files changed

+80
-38
lines changed

3 files changed

+80
-38
lines changed

sp/src/public/vscript/ivscript.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,18 +263,22 @@ inline const char * ScriptFieldTypeName( int16 eType)
263263

264264
//---------------------------------------------------------
265265

266+
struct ScriptClassDesc_t;
267+
266268
struct ScriptFuncDescriptor_t
267269
{
268270
ScriptFuncDescriptor_t()
269271
{
270272
m_pszFunction = NULL;
271273
m_ReturnType = FIELD_TYPEUNKNOWN;
272274
m_pszDescription = NULL;
275+
m_pScriptClassDesc = NULL;
273276
}
274277

275278
const char *m_pszScriptName;
276279
const char *m_pszFunction;
277280
const char *m_pszDescription;
281+
ScriptClassDesc_t *m_pScriptClassDesc;
278282
ScriptDataType_t m_ReturnType;
279283
CUtlVector<ScriptDataType_t> m_Parameters;
280284
};

sp/src/public/vscript/vscript_templates.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_TYPE_DEDUCER );
6161

6262
FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNC_TYPE_DEDUCER );
6363

64-
#define ScriptInitMemberFuncDescriptor_( pDesc, class, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, (class *)(0), &class::func ); }
64+
#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); }
6565

6666
#define ScriptInitFuncDescriptorNamed( pDesc, func, scriptName ) if ( 0 ) {} else { (pDesc)->m_pszScriptName = scriptName; (pDesc)->m_pszFunction = #func; ScriptDeduceFunctionSignature( pDesc, &func ); }
6767
#define ScriptInitFuncDescriptor( pDesc, func ) ScriptInitFuncDescriptorNamed( pDesc, func, #func )

sp/src/vscript/vscript_squirrel.cpp

Lines changed: 75 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,16 @@ namespace SQVector
327327
}
328328

329329
SQUserPointer p;
330-
sq_getinstanceup(vm, 1, &p, 0);
330+
if (SQ_FAILED(sq_getinstanceup(vm, 1, &p, 0)))
331+
{
332+
return SQ_ERROR;
333+
}
334+
335+
if (!p)
336+
{
337+
return sq_throwerror(vm, "Accessed null instance");
338+
}
339+
331340
new (p) Vector(x, y, z);
332341

333342
return 0;
@@ -343,7 +352,7 @@ namespace SQVector
343352
return sq_throwerror(vm, "Expected Vector._get(string)");
344353
}
345354

346-
if (key[0] < 'x' || key['0'] > 'z' || key[1] != '\0')
355+
if (key[0] < 'x' || key[0] > 'z' || key[1] != '\0')
347356
{
348357
return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
349358
}
@@ -369,7 +378,7 @@ namespace SQVector
369378
return sq_throwerror(vm, "Expected Vector._set(string)");
370379
}
371380

372-
if (key[0] < 'x' || key['0'] > 'z' || key[1] != '\0')
381+
if (key[0] < 'x' || key[0] > 'z' || key[1] != '\0')
373382
{
374383
return sqstd_throwerrorf(vm, "the index '%.50s' does not exist", key);
375384
}
@@ -1291,10 +1300,7 @@ bool getVariant(HSQUIRRELVM vm, SQInteger idx, ScriptVariant_t& variant)
12911300
case OT_INSTANCE:
12921301
{
12931302
Vector* v = nullptr;
1294-
SQUserPointer tag;
1295-
if (SQ_SUCCEEDED(sq_gettypetag(vm, idx, &tag)) &&
1296-
tag == TYPETAG_VECTOR &&
1297-
SQ_SUCCEEDED(sq_getinstanceup(vm, idx, (SQUserPointer*)&v, TYPETAG_VECTOR)))
1303+
if (SQ_SUCCEEDED(sq_getinstanceup(vm, idx, (SQUserPointer*)&v, TYPETAG_VECTOR)))
12981304
{
12991305
variant.Free();
13001306
variant = (Vector*)malloc(sizeof(Vector));
@@ -1323,12 +1329,10 @@ SQInteger function_stub(HSQUIRRELVM vm)
13231329
{
13241330
SQInteger top = sq_gettop(vm);
13251331

1326-
SQUserPointer userptr = nullptr;
1327-
sq_getuserpointer(vm, top, &userptr);
1328-
1329-
Assert(userptr);
1332+
ScriptFunctionBinding_t* pFunc = nullptr;
1333+
sq_getuserpointer(vm, top, (SQUserPointer*)&pFunc);
13301334

1331-
ScriptFunctionBinding_t* pFunc = (ScriptFunctionBinding_t*)userptr;
1335+
Assert(pFunc);
13321336

13331337
int nargs = pFunc->m_desc.m_Parameters.Count();
13341338
int nLastHScriptIdx = -1;
@@ -1424,15 +1428,30 @@ SQInteger function_stub(HSQUIRRELVM vm)
14241428

14251429
if (pFunc->m_flags & SF_MEMBER_FUNC)
14261430
{
1427-
SQUserPointer self;
1428-
sq_getinstanceup(vm, 1, &self, nullptr);
1431+
ClassInstanceData* classInstanceData;
1432+
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
1433+
{
1434+
return SQ_ERROR;
1435+
}
14291436

1430-
if (!self)
1437+
if (!classInstanceData)
14311438
{
14321439
return sq_throwerror(vm, "Accessed null instance");
14331440
}
14341441

1435-
instance = ((ClassInstanceData*)self)->instance;
1442+
// check that the type of self, or any basetype, matches the function description
1443+
ScriptClassDesc_t *selfType = classInstanceData->desc;
1444+
while (selfType != pFunc->m_desc.m_pScriptClassDesc)
1445+
{
1446+
if (!selfType)
1447+
{
1448+
return sq_throwerror(vm, "Mismatched instance type");
1449+
}
1450+
selfType = selfType->m_pBaseDesc;
1451+
Assert(selfType != classInstanceData->desc); // there should be no infinite loop
1452+
}
1453+
1454+
instance = classInstanceData->instance;
14361455
}
14371456

14381457
ScriptVariant_t script_retval;
@@ -1441,8 +1460,6 @@ SQInteger function_stub(HSQUIRRELVM vm)
14411460
SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getsharedforeignptr(vm);
14421461
Assert(pSquirrelVM);
14431462

1444-
sq_resetobject(&pSquirrelVM->lastError_);
1445-
14461463
bool call_success = (*pFunc->m_pfnBinding)(pFunc->m_pFunction, instance, params.Base(), nargs,
14471464
pFunc->m_desc.m_ReturnType == FIELD_VOID ? nullptr : &script_retval, script_retval_storage);
14481465
Assert(call_success);
@@ -1452,6 +1469,7 @@ SQInteger function_stub(HSQUIRRELVM vm)
14521469
if (!sq_isnull(pSquirrelVM->lastError_))
14531470
{
14541471
sq_pushobject(vm, pSquirrelVM->lastError_);
1472+
sq_release(vm, &pSquirrelVM->lastError_);
14551473
sq_resetobject(&pSquirrelVM->lastError_);
14561474
sq_retval = sq_throwobject(vm);
14571475
}
@@ -1521,28 +1539,42 @@ SQInteger destructor_stub_instance(SQUserPointer p, SQInteger size)
15211539
SQInteger constructor_stub(HSQUIRRELVM vm)
15221540
{
15231541
ScriptClassDesc_t* pClassDesc = nullptr;
1524-
sq_gettypetag(vm, 1, (SQUserPointer*)&pClassDesc);
1542+
if (SQ_FAILED(sq_gettypetag(vm, 1, (SQUserPointer*)&pClassDesc)))
1543+
{
1544+
return sq_throwerror(vm, "Expected native class");
1545+
}
1546+
1547+
if (!pClassDesc || (void*)pClassDesc == TYPETAG_VECTOR)
1548+
{
1549+
return sq_throwerror(vm, "Unable to obtain native class description");
1550+
}
15251551

15261552
if (!pClassDesc->m_pfnConstruct)
15271553
{
15281554
return sqstd_throwerrorf(vm, "Unable to construct instances of %s", pClassDesc->m_pszScriptName);
15291555
}
15301556

1531-
SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getsharedforeignptr(vm);
1532-
Assert(pSquirrelVM);
1557+
SQUserPointer p;
1558+
if (SQ_FAILED(sq_getinstanceup(vm, 1, &p, 0)))
1559+
{
1560+
return SQ_ERROR;
1561+
}
15331562

1534-
sq_resetobject(&pSquirrelVM->lastError_);
1563+
if (!p)
1564+
{
1565+
return sq_throwerror(vm, "Accessed null instance");
1566+
}
15351567

15361568
void* instance = pClassDesc->m_pfnConstruct();
15371569

1570+
#ifdef DBGFLAG_ASSERT
1571+
SquirrelVM* pSquirrelVM = (SquirrelVM*)sq_getsharedforeignptr(vm);
1572+
Assert(pSquirrelVM);
15381573
// expect construction to always succeed
15391574
Assert(sq_isnull(pSquirrelVM->lastError_));
1575+
#endif
15401576

1541-
{
1542-
SQUserPointer p;
1543-
sq_getinstanceup(vm, 1, &p, 0);
1544-
new(p) ClassInstanceData(instance, pClassDesc, nullptr, true);
1545-
}
1577+
new(p) ClassInstanceData(instance, pClassDesc, nullptr, true);
15461578

15471579
sq_setreleasehook(vm, 1, &destructor_stub);
15481580

@@ -1552,7 +1584,10 @@ SQInteger constructor_stub(HSQUIRRELVM vm)
15521584
SQInteger tostring_stub(HSQUIRRELVM vm)
15531585
{
15541586
ClassInstanceData* classInstanceData = nullptr;
1555-
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
1587+
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
1588+
{
1589+
return SQ_ERROR;
1590+
}
15561591

15571592
char buffer[128] = "";
15581593

@@ -1582,7 +1617,10 @@ SQInteger tostring_stub(HSQUIRRELVM vm)
15821617
SQInteger get_stub(HSQUIRRELVM vm)
15831618
{
15841619
ClassInstanceData* classInstanceData = nullptr;
1585-
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
1620+
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
1621+
{
1622+
return SQ_ERROR;
1623+
}
15861624

15871625
const char* key = nullptr;
15881626
sq_getstring(vm, 2, &key);
@@ -1614,7 +1652,10 @@ SQInteger get_stub(HSQUIRRELVM vm)
16141652
SQInteger set_stub(HSQUIRRELVM vm)
16151653
{
16161654
ClassInstanceData* classInstanceData = nullptr;
1617-
sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0);
1655+
if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer*)&classInstanceData, 0)))
1656+
{
1657+
return SQ_ERROR;
1658+
}
16181659

16191660
const char* key = nullptr;
16201661
sq_getstring(vm, 2, &key);
@@ -2710,10 +2751,8 @@ void SquirrelVM::SetInstanceUniqeId(HSCRIPT hInstance, const char* pszId)
27102751
HSQOBJECT* obj = (HSQOBJECT*)hInstance;
27112752
sq_pushobject(vm_, *obj);
27122753

2713-
SQUserPointer self;
2714-
sq_getinstanceup(vm_, -1, &self, nullptr);
2715-
2716-
auto classInstanceData = (ClassInstanceData*)self;
2754+
ClassInstanceData* classInstanceData;
2755+
sq_getinstanceup(vm_, -1, (SQUserPointer*)&classInstanceData, nullptr);
27172756

27182757
classInstanceData->instanceId = pszId;
27192758

@@ -2771,11 +2810,10 @@ void* SquirrelVM::GetInstanceValue(HSCRIPT hInstance, ScriptClassDesc_t* pExpect
27712810
}
27722811

27732812
sq_pushobject(vm_, *obj);
2774-
SQUserPointer self;
2775-
sq_getinstanceup(vm_, -1, &self, nullptr);
2813+
ClassInstanceData* classInstanceData;
2814+
sq_getinstanceup(vm_, -1, (SQUserPointer*)&classInstanceData, nullptr);
27762815
sq_pop(vm_, 1);
27772816

2778-
auto classInstanceData = (ClassInstanceData*)self;
27792817

27802818
if (!classInstanceData)
27812819
{

0 commit comments

Comments
 (0)