Jump to content
  • Advertisement
Sign in to follow this  
GuyWithBeard

Refcount mismatch when discarding module.

This topic is 906 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

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!

Share this post


Link to post
Share on other sites
Advertisement

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?

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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]

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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

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.

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!