Jump to content
  • Advertisement
Sign in to follow this  
AgentC

Crash with temporary value types and unsafe references

This topic is 2592 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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);

Share this post


Link to post
Share on other sites
Advertisement
I found out that the crash can also be circumvented by compiling AngelScript with AS_OLD defined, enabling the old return value code.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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);

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!