My application is experiencing a crash in a template object's factory, because the asITypeInfo pointer being passed to the factory does not have a valid subtype. I've tried to track down the cause of this bug, and I suspect that the reference counting of template function return types may be incorrect.
When a module contains a template instantiation, function objects are added to the script engine. Building a second module with an identical script will reuse those function objects. After discarding the first module though, the return types of those function objects are no longer valid. Below I have constructed a simple example which crashes due to a null engine pointer in the return type of a factory function.
class MyTmpl
{
public:
MyTmpl(asITypeInfo *t)
{
refCount = 1;
type = t;
OutputDebugStringA(asGetActiveContext()->GetFunction(0)->GetDeclaration());
type->AddRef();
}
~MyTmpl()
{
if( type )
type->Release();
}
void AddRef()
{
refCount++;
}
void Release()
{
if( --refCount == 0 )
delete this;
}
asITypeInfo *type;
int refCount;
};
MyTmpl *MyTmpl_factory(asITypeInfo *type)
{
return new MyTmpl(type);
}
asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->RegisterObjectType("MyTmpl<class T>", 0, asOBJ_REF | asOBJ_TEMPLATE);
engine->RegisterObjectBehaviour("MyTmpl<T>", asBEHAVE_FACTORY, "MyTmpl<T> @f(int&in)", asFUNCTIONPR(MyTmpl_factory, (asITypeInfo*), MyTmpl*), asCALL_CDECL);
engine->RegisterObjectBehaviour("MyTmpl<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(MyTmpl, AddRef), asCALL_THISCALL);
engine->RegisterObjectBehaviour("MyTmpl<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(MyTmpl, Release), asCALL_THISCALL);
asIScriptModule *mod1 = engine->GetModule("m1", asGM_ALWAYS_CREATE);
asIScriptModule *mod2 = engine->GetModule("m2", asGM_ALWAYS_CREATE);
const char* script_text = "void main() { MyTmpl<int> s; }";
mod1->AddScriptSection("test1", script_text);
mod1->Build();
mod2->AddScriptSection("test2", script_text);
mod2->Build();
mod1->Discard();
asIScriptContext *ctx = engine->CreateContext();
asIScriptFunction *func = mod2->GetFunctionByDecl("void main()");
ctx->Prepare(func);
ctx->Execute();
ctx->Release();
engine->Release();