References as return values: assertions and crashes
Hello,
I'm a newbie to AngelScript, so maybe there is something that I simply don't understand or don't know. The problem is: if I use references as return values, no matter in what context, compiler keeps crashing during execution or during compilation.
I come up with this code to reproduce crash (with AngelScript compiled from recent SVN revision):
string& SomeFunc()
{
return "";
}
void main()
{
string s = SomeFunc();
}
And with somewhat more verbose code to reproduce assertion:
// Output:
// My class constructed
// My class constructed with param: 42
// Assertion failed: other.objType->DerivesFrom(objType), file ..\..\source\as_scriptstruct.cpp, line 438
class MyClass
{
int id;
MyClass()
{
print("My class constructed\n");
}
MyClass(int arg)
{
id = arg;
print("My class constructed with param: " + id + "\n");
}
}
MyClass& SomeFunc()
{
return MyClass(42);
}
void main()
{
MyClass m = SomeFunc();
}
You need to understand how the following is processed in order to know why it's crashing:
The problem here is that MyClass(42) creates an object of type MyClass on the stack. As soon as SomeFunc() returns the MyClass object is destroyed, as all objects in that stackframe are popped off.
So now, outside of SomeFunc the caller has a reference to an invalid object, hence the crash, or in general the outcome is undefined.
As a general rule, you never return references to local objects.
MyClass& SomeFunc(){ return MyClass(42);}
The problem here is that MyClass(42) creates an object of type MyClass on the stack. As soon as SomeFunc() returns the MyClass object is destroyed, as all objects in that stackframe are popped off.
So now, outside of SomeFunc the caller has a reference to an invalid object, hence the crash, or in general the outcome is undefined.
As a general rule, you never return references to local objects.
Yes, I haven't experience with C++ as well. :) But initially I added destructor to class definition:
~MyClass()
{
print("My class destructed\n");
}
And if I had seen this message in output, I shouldn't have posted this report.
~MyClass()
{
print("My class destructed\n");
}
And if I had seen this message in output, I shouldn't have posted this report.
And about compilation errors. As I can see, it's not related to references though.
I get this message:
for following (synthetic) code:
I get this message:
Assertion failed: tempVariables.GetLength() == 0, file ..\..\source\as_compiler.cpp, line 614
for following (synthetic) code:
string SomeFunc(){ return null;}void main(){}
All assert failures in the library indicates some bug. I'll take a look at this at the earliest possible moment.
However, I can tell you already that the script language doesn't support returning references yet. This is because it requires careful checking of what the reference actually points to, so that it can be guaranteed that the reference is valid after the function returns.
However, I can tell you already that the script language doesn't support returning references yet. This is because it requires careful checking of what the reference actually points to, so that it can be guaranteed that the reference is valid after the function returns.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
Quote: Original post by marvi
And about compilation errors. As I can see, it's not related to references though.
I get this message:Assertion failed: tempVariables.GetLength() == 0, file ..\..\source\as_compiler.cpp, line 614
for following (synthetic) code:string SomeFunc(){ return null;}void main(){}
To fix this bug, apply the following changes to as_compiler.cpp near line 1147:
void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, asCArray<int> *reservedVars){ ... // Need to protect arguments by reference if( isFunction && dt.IsReference() ) { ... } else { if( dt.IsPrimitive() ) { ... } else { IsVariableInitialized(&ctx->type, node); // Implicitly convert primitives to the parameter type ImplicitConversion(ctx, dt, node, false, true, reservedVars);Add this code --->> // Was the conversion successful? if( !ctx->type.dataType.IsEqualExceptRef(dt) ) { asCString str; str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf()); Error(str.AddressOf(), node); ctx->type.Set(dt); }<<--- ... } } // Don't put any pointer on the stack yet if( param.IsReference() || param.IsObject() ) { // &inout parameter may leave the reference on the stack already if( refType != 3 ) { ctx->bc.Pop(PTR_SIZE); ctx->bc.InstrSHORT(BC_VAR, ctx->type.stackOffset); } ProcessDeferredParams(ctx); }}
Hopefully I'll be able to check in this fix soon.
I still need to investigate the first bug you reported. I'll let you know as soon as I have the solution for it.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
I've checked in fixes for both problems now.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement