Refcount mismatch when discarding module.

Started by
8 comments, last by GuyWithBeard 8 years ago

I get an assert failure in debug mode when I discard of my script modules. I have a very minimal test case where I can reproduce the assert failure easily. The code works as intended but it makes me wonder if I am doing everything correctly.

The complete script in this case is a one line thing like this:


float time = 0.0f;

I am using the CScriptBuilder add-on to build the thing. Basically calling StartNewModule(), AddSectionFromMemory() supplying the above code string, BuildModule() and finally GetModule() to get the compiled module. BuildModule() returns 0.

If I immediately call Discard() on the module I get an assert in as_module.cpp, line 741. The expression is "asASSERT( (*globIt)->refCount.get() == 1 );"

Looking at the script module in the watch window the scriptGlobals array has one entry with the name "time" and refCount 2.

Should I somehow be releasing the global variables before calling Discard? I apologize if this is explained in the tutorial, I could not find anything related to this.

Cheers!

Advertisement

Oh, and the version of AS I am using is 2.30.2.

Looking at the code for asCModule::AllocateGlobalProperty(), the call to engine->AllocateGlobalProperty() returns a new property with a ref count of 1. Right before asCModule::AllocateGlobalProperty() returns it increments the ref count to 2, which would explain why it fails the assert. Again, I am not sure if I am supposed to decrement it somehow before calling Discard() on the module.

Thoughts?

An assert error within the script engine usually means that there is a bug in the engine.

I will have to investigate this, and will update you when I have any information on the cause and/or fix.

In the mean time, have you tried the latest version of the library? There is a chance that the problem has already been fixed (though I wasn't aware of this specific case).

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 have not tried the latest version. I am in the middle of a fairly large reworking of my code at the moment. Let me know if you can repro the assert failure, and if you cant I will update to the latest version.

I couldn't reproduce this with the latest revision. I tried with the following snippet, perhaps you can identify something that you're doing differently. But it's more likely that this problem has already been fixed.

[source]

{
asIScriptEngine *engine = asCreateScriptEngine();
engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
CScriptBuilder b;
b.StartNewModule(engine, "test");
b.AddSectionFromMemory("test", "float test = 0.0f;");
r = b.BuildModule();
if (r < 0)
TEST_FAILED;
asIScriptModule *mod = b.GetModule();
mod->Discard();
engine->ShutDownAndRelease();
}

[/source]

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 have tracked it down to my context pooling. I am using the context callbacks mechanism to manage a pool of (currently eight) contexts to make it possible do coroutines later. Currently only one context is every used at a time, which means that the first context in the pool is the one that will be returned over and over again. The assert failure occurs when the context outlives the script module.

Try this:


{
    class Dummy
    {
    public:
        static asIScriptContext* requestScriptContext(asIScriptEngine* engine, void* param)
        {
            return static_cast<asIScriptContext*>(param);
        }

        static void returnScriptContext(asIScriptEngine* engine, asIScriptContext* context, void* param)
        {
            // Nothing to do...
        }
    };

    asIScriptEngine *engine = asCreateScriptEngine();
    engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

    asIScriptContext* ctxt = engine->CreateContext();
    engine->SetContextCallbacks(Dummy::requestScriptContext, Dummy::returnScriptContext, ctxt);

    CScriptBuilder b;
    b.StartNewModule(engine, "test");
    b.AddSectionFromMemory("test", "float test = 0.0f;");
    int r = b.BuildModule();
    if (r < 0)
        TEST_FAILED;

    asIScriptModule *mod = b.GetModule();
    mod->Discard();

    ctxt->Release();
    engine->ShutDownAndRelease();
}

In my code base, script modules are potentially very short-lived as one game object gets its own isolated script module. The contexts on the other hand are created on startup and stays alive until the app is shut down.

Thanks. I believe I understand where the problem lies now. I'll give this a try tonight when I get home.

I also believe I know how you can work around the problem. In your returnScriptContext callback, you should call context->Unprepare() to tell the context to release references to whatever functions it was calling (in this case the implicit function used to initialize the global variable).

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 fixed the bug in revision 2309.

If you don't want to upgrade to the latest revision from the SVN, you ought to be able to apply this fix locally to version 2.30.2.

https://sourceforge.net/p/angelscript/code/2309/tree//trunk/sdk/angelscript/source/as_module.cpp?diff=2274

Regards,

Andreas

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

Cool, thanks!

This topic is closed to new replies.

Advertisement