Hello! It seems that if a variadic function returns an object on the stack, it causes a crash when calling SetReturnObject in asIScriptGeneric object.
If I'm not mistaking, the data for the variadic function on the stack is like this:
[{return object address}, {arguments count}, {arguments values}]
stackPointer in the asCGeneric object points to the beginning of args values, but receiving the address of returning object is calculated as “(void*)*(asPWORD*)(stack Pointer - AS_PTR_SIZE)”. This expression does not take into account that before the values of the arguments there is also the number of arguments themselves. To solve the problem, it seems that it is enough to simply subtract an additional 4 bytes if the function is variadic. Here is the code for the changed functions:
int asCGeneric::SetReturnObject(void *obj)
{
...
else
{
int variadicSizeParameterOffset = sysFunction->IsVariadic() ? 1 : 0;
// If function returns object by value the memory is already allocated.
// Here we should just initialize that memory by calling the copy constructor
// or the default constructor followed by the assignment operator
void *mem = (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE - variadicSizeParameterOffset];
engine->ConstructScriptObjectCopy(mem, obj, CastToObjectType(dt->GetTypeInfo()));
return 0;
}
objectRegister = obj;
return 0;
}
void *asCGeneric::GetAddressOfReturnLocation()
{
asCDataType &dt = sysFunction->returnType;
if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() )
{
if( sysFunction->DoesReturnOnStack() )
{
int variadicSizeParameterOffset = sysFunction->IsVariadic() ? 1 : 0;
// The memory is already preallocated on the stack,
// and the pointer to the location is found before the first arg
return (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE - variadicSizeParameterOffset];
}
// Reference types store the handle in the objectReference
return &objectRegister;
}
// Primitive types and references are stored in the returnVal property
return &returnVal;
}