Jump to content
  • Advertisement
Miss

Refcounting in opCast

Recommended Posts

I have an function declaration of "void opCast(?&out)" on a class with asOBJ_REF, and I'm running into an interesting problem.

In 1 very specific case, (I can't seem to reproduce it in a clean test script), there seems to be either an AddRef too many or a Release too little.

I can fix it by making a small change to my script. The following causes there to be 5 AddRef's, and 5 Releases, which is the expected behavior:

auto a = g_scene.Mobils[0];
auto b = cast<CControlBase>(a);
if (b !is null) {
  // ...
} else {
  // ...
}

But the following produces 5 AddRef's and 4 Releases:

auto b = cast<CControlBase>(g_scene.Mobils[0]);
if (b !is null) {
  // ...
} else {
  // ...
}

I checked if the typeId happens to be different in the opCast function (thought maybe const could be at play or so) but it seems like that's the same in both situations. I do an AddRef myself in the opCast function when returning the casted handle.

Share this post


Link to post
Share on other sites
Advertisement

g_scene.Mobils is a CScriptArray? What is the type of the elements?

I'll try to reproduce the problem.

 

Share this post


Link to post
Share on other sites

No, it's actually a custom class "MwBuffer". The interface is documented here: https://openplanet.nl/docs/class/MwBuffer

The code for opIndex looks like this:

static void ScriptBufferIndexer(asIScriptGeneric* gen)
{
	CFastBufferBase* self = (CFastBufferBase*)gen->GetObject();
	int dwIndex = gen->GetArgDWord(0);

	if (dwIndex >= self->m_Count) {
		asGetActiveContext()->SetException("Index out of range in buffer");
		return;
	}

	int returnTypeId = gen->GetReturnTypeId();
	asUINT typeSize = 4;
	if (!(returnTypeId & asTYPEID_OBJHANDLE)) {
		typeSize = GetTypeSize(gen->GetEngine(), gen->GetReturnTypeId());
	}

	void* pObj = (char*)self->m_elements + typeSize * dwIndex;
	gen->SetReturnAddress(pObj);
}

 

Share this post


Link to post
Share on other sites

Thanks. 

I see nothing wrong in your code. I suspect it may be a bug related to how the compiler treats temporary variables. I'll investigate further and let you know.

Share this post


Link to post
Share on other sites

I've managed to reproduce the problem. It is indeed a bug in the compiler. I even get an assert failure in the compiler when running in debug mode.

I'll have a fix available in the next few days.

Share this post


Link to post
Share on other sites
external shared class A;
A@ a = cast<A>(GetA());

With the revision of rev 2509, when there is initialization of the global variable as described above, it outputs and stops as follows.

Assertion failed: tempVariables.Exists(offset), file j:\home\src\angelscript\sdk\angelscript\source\as_compiler.cpp, line 5333

The following is a fragment of the test code executed.

#include "../../../add_on/scriptany/scriptany.h"
...snip...
static void CScriptAny_Cast(void *ref, int refTypeId, void *x)
{
  if(!((CScriptAny*)x)->Retrieve(ref, refTypeId))
  {
    asIScriptContext *ctx = asGetActiveContext();
    if( ctx )
      ctx->SetException("Illegal conversion");
  }
}

static void *GetA()
{
  return nullptr;
}

bool Test()
{
...snip...
        RegisterScriptAny(engine);

        r = engine->RegisterObjectMethod("any", "void opCast(?&out)", asFUNCTION(CScriptAny_Cast), asCALL_CDECL_OBJLAST); assert( r >= 0 );

        r = engine->RegisterGlobalFunction(
                       "any@ GetA()"
                     , asFUNCTION(GetA)
                     , asCALL_CDECL
                     );
		if (r < 0)
			TEST_FAILED;

		mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"shared class A {"
            "};"
         );
		r = mod->Build();
		if (r < 0)
			TEST_FAILED;

		asIScriptModule *mod2 = engine->GetModule("test2", asGM_ALWAYS_CREATE);
		mod2->AddScriptSection("test",
			"external shared class A;"
            "A@ a = cast<A>(GetA());"
		);
		r = mod2->Build();
		if (r < 0)
			TEST_FAILED;

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!