Advertisement

crash when caching engine->GetTypeIdByDecl()

Started by February 21, 2014 10:12 PM
7 comments, last by WitchLord 10 years, 9 months ago

I'm using 2.28.1 WIP on debug, 32-bit windows 7.

I have a wrapper function around engine->GetTypeIdByDecl() along these lines:


i32 GetEngineTypeIdFromDecl(string s)
{
  if ( s is in container )
    // return cached int from container
  else
  {
    // call engine->GetTypeIdByDecl(s)
    // add int to container
    // return int
  }
}

I've run into a crash in engine->GetObjectTypeById():


asIObjectType *asCScriptEngine::GetObjectTypeById(int typeId) const
{
	asCDataType dt = GetDataTypeFromTypeId(typeId);

	// Is the type id valid?
	if( !dt.IsValid() ) return 0;

	// Enum types are not objects, so we shouldn't return an object type for them
	if( dt.GetObjectType() && dt.GetObjectType()->GetFlags() & asOBJ_ENUM )
		return 0;

	return dt.GetObjectType();
}

dt, as it comes back from GetDataTypeFromTypeId(typeId) is a garbage instance.. it passes the valid check but crashes in the dt.GetObjectType()-> call.. I noticed in the debugger that many of dt's variables are 0xfeeefeee which VS's debug allocator uses to indicate that you're pointing to deleted heap memory.

Here is what I'm doing:


void MyExecuteScriptFunction(functionName, paramsForFunction)
{
    // this potentially returns a cached typeid
    i32 myArrayTypeId = GetEngineTypeIdFromDecl("array<MyType@>@");

    // the second time I run through this code, the below call crashes:
    asIObjectType* type engine->GetObjectTypeById(myArrayTypeId);

    CScriptArray* arr = new CScriptArray(0, type);

    // fill array with some stuff, pass it to a script function, execute function

    arr->Release();
}

I can get around the crash either by leaking the CScriptArray, which means its dtor doesn't run and it doesn't call Release() on the object type, or I can avoid caching the results of engine->GetTypeIdByDecl() and call it every time.


CScriptArray::~CScriptArray()
{
    ...
    if( objType ) objType->Release();
}

Since the AngelScript documentation suggests caching the results of engine->GetTypeIdByDecl(), am I doing anything wrong above? Is there any way for me to know that my cached type id has been invalidated?

Thank you very much.

The object type for array<MyType@> has probably been removed, e.g if the script that declared the MyType is recompiled, so the typeId you cached is no longer valid.

Of course, the GetObjectTypeById shouldn't crash when giving invalid type id's, instead it should return a null pointer. I'll need to look into why it crashes.

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

Advertisement

I didn't even think to mention it, but yes, I was recompiling the script!

So what you're saying is that my one script was the only one referencing the array<MyType@> type and when the script went away, the type was released...

By the way, when I'm looking up either "MyType&" or "array<MyType@>@" should I be specifying a reference or handle on the type? Would it be more correct to look up "MyType" and "array<MyType@>"? What I'm doing is trying to match a script-function's parameter with one of the types that I know. So if the script function is: void foo(array<MyType@>@) would I want to look up "array<MyType@>@" or "array<MyType@>" ?

Thank you very much!

Exactly, if there were no live objects of either the MyType type or the array<MyType@> type, then when you discarded the script (or recompiled it) the object types are released as they won't be used any longer.

If you do not want the object type to be release, you can hold on to the asIObjectType by increasing the reference count. It will then keep the type and related script code in memory until you release the object.

Observe however, when you recompile the script, the old types will be incompatible with the new ones (unless declared as shared), even though they are compiled from the same source code. Both the asIObjectType and the typeId will be different.

The type id for array<MyType@>@ and array<MyType@> are different, but the only difference is the bit asTYPEID_OBJHANDLE, so you can easily derive one from the other.

However, in your case, it is not really the type id that you want. You want the asIObjectType so you can create the CScriptArray. You can get this with GetObjectTypeByName("array<MyType@>") so you don't even need to retrieve the type id first. It's still a good idea to cache the returned asIObjectType though.

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 crash in GetObjectTypeById in revision 1850. Now it will properly return a null pointer to inform the caller that the object type doesn't exist anymore.

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

Thank you for the fix!

If I'm doing something like:


int paramTypeId = scriptFunc->GetParamTypeId(0);

And I want to enforce that 'paramTypeId' is of type array handle (I don't care, at this point, what it's an array of.. I'll validate the subtype later. I just want to know that it's an array handle), what syntax would I use? GetObjectTypeByName("array<>@") ? GetObjectTypeByName("array<?>@")

UPDATE: Apparently asIObjectType* arrayType = scriptEngine->GetObjectTypeByName("array"); works just fine. Is there any way to tell whether the script-function is taking this array by handle, instead of by value?

Advertisement

You can it like this:

bool isHandle = (paramTypeId & asTYPEID_OBJHANDLE) ? true : false;
 
asIObjectType *type = engine->GetObjectTypeById(paramTypeId);
bool isArray = (type && strcmp(type->GetName(), "array") == 0) ? true : false;

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

GetObjectTypeByName("array<MyType@>") doesn't seem to work. I've got the following tests:


scriptEngine->GetObjectTypeByName("array");                                         // non-NULL address 1
scriptEngine->GetObjectTypeByName("array<MyType@>");                                // NULL
scriptEngine->GetObjectTypeByName("array<MyType@>@");                               // NULL

scriptEngine->GetObjectTypeById(scriptEngine->GetTypeIdByDecl("array"));            // NULL
scriptEngine->GetObjectTypeById(scriptEngine->GetTypeIdByDecl("array<MyType@>"));   // non-NULL address 2
scriptEngine->GetObjectTypeById(scriptEngine->GetTypeIdByDecl("array<MyType@>@"));  // non-NULL address 2

So if you want to check whether a type is "array", regardless of subtype, it seems that you need to use GetObjectTypeByName(). If you want to check what the actual array-plus-subtype is, it seems that you need to use the declaration instead of the name, like GetObjectTypeById(GetTypeIdByDecl()).

Am I doing something wrong?

Yes, that's true. Sorry for misleading you earlier.

GetObjectTypeByName() only accepts a single name for the lookup, it doesn't accept a type declaration, so it cannot be used to get the template instance type, e.g. array<int> array<MyType@>, etc.

I'll probably add a GetObjectTypeByDecl() for release 2.29.0 to better support this scenario.

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

This topic is closed to new replies.

Advertisement