Crash with temporary value types and unsafe references

Started by
5 comments, last by AgentC 12 years, 5 months ago
Hi,
I have a system where for example scene nodes' properties can be accessed generically through a Variant value type, which can return an unsafe reference to the actual data it's holding (for example a String, 3D vector, or another Variant)

After migrating from AngelScript 2.21.1 to 2.22.0 I'm seeing a crash with the following code: (note that the actual C++ implementation of the Variant class is "safe" in such manner that if you query a Variant for a String when it's actually holding something else, you get a reference to a pre-created dummy string)


Node@ node = Node("Test"); // Create a dummy scene node
String str = node.attributes[0].GetString(); // Get its first attribute as a string


The execution of the code will later crash in the String destructor. I'm not able to see which string object it's actually trying to destroy.

The workaround is to actually create a local variable for the Variant object, and then it doesn't crash:


Node@ node = Node("Test"); // Create a dummy scene node
Variant value = node.attributes[0]; // Get its first attribute
String str = value.GetString(); // Get the string value from the variant


Also, another workaround which makes the crash go away is to actually make Variant return a copy of the String in GetString(), instead of a reference. But for speed optimization and to not need wrapper code I'd rather keep the unsafe reference.

The relevant class registration code is:


engine->RegisterObjectType("String", sizeof(String), asOBJ_VALUE | asOBJ_APP_CLASS_CDA);
engine->RegisterStringFactory("String", asFUNCTION(StringFactory), asCALL_CDECL);
engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(const String&in)", asFUNCTION(ConstructStringCopy), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("String", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST);

engine->RegisterObjectType("Variant", sizeof(Variant), asOBJ_VALUE | asOBJ_APP_CLASS_CDA);
engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructVariant), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(const Variant&in)", asFUNCTION(ConstructVariantCopy), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("Variant", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructVariant), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Variant", "const String& GetString() const", asMETHOD(Variant, GetString), asCALL_THISCALL);

engine->RegisterObjectType("Node", 0, asOBJ_REF);
engine->RegisterObjectMethod("Node", "Variant get_attributes(uint) const", asMETHODPR(Node, GetAttribute, (unsigned), Variant), asCALL_THISCALL);
Advertisement
I found out that the crash can also be circumvented by compiling AngelScript with AS_OLD defined, enabling the old return value code.
Thanks. I'll investigate this problem.

I noticed that your String and Variant type doesn't have the opAssign method. Is this true, or did you just leave it out when writing the post?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Ah sorry, they do have assignment operators. And actually quite many overloads for it :) but here's at least the basic forms:


engine->RegisterObjectMethod("Variant", "Variant& opAssign(const Variant&in)", asMETHODPR(Variant, operator =, (const Variant&), Variant&), asCALL_THISCALL);
engine->RegisterObjectMethod("String", "String& opAssign(const String&in)", asMETHODPR(String, operator =, (const String&), String&), asCALL_THISCALL);
I've been able to reproduce this problem. Thanks for the clear report.

I'm still investigating the code, but it seems to be related with how the compiler is treating the returned reference from the temporary variant allocated on the stack. When invoking the opAssign of the string str as part of the variable initialization the reference on the stack is actually to the Variant, not the string reference it returned.

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 bug has now been fixed in revision 1036.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks, it works awesomely now!

This topic is closed to new replies.

Advertisement