Hi,
for some time I've been unable to migrate to newer versions of AngelScript due to a tempVariables assertion I'm getting in debug mode (at least VS2008). I finally managed to make a stand-alone reproduction case. The example contains a lot of missing/stub functionality that would crash if actually run, but please don't mind that
The assertion I'm getting is: tempVariables.Exists(offset), file ..\..\source\as_compiler.cpp, line 4840, using the newest SVN revision. The code is also using the scriptarray add-on.
As far as I understand, it's the assigning to an unsafely referenced value type, that has been acquired with a nested indexing, that causes the assert.
#include <angelscript.h>
#include <string>
#include "scriptarray.h"
using namespace std;
class String
{
public:
bool Empty() const { return true; }
};
static String StringFactory(asUINT length, const char* s)
{
return String();
}
static void ConstructString(String* ptr)
{
new(ptr) String();
}
static void ConstructStringCopy(const String& str, String* ptr)
{
new(ptr) String(str);
}
static void DestructString(String* ptr)
{
ptr->~String();
}
class ShortStringHash
{
public:
ShortStringHash() {}
ShortStringHash(const String& str) {}
};
static void ConstructShortStringHash(ShortStringHash* ptr)
{
new(ptr) ShortStringHash();
}
class Variant
{
};
static void ConstructVariant(Variant* ptr)
{
new(ptr) Variant();
}
static void ConstructVariantCopy(const Variant& variant, Variant* ptr)
{
new(ptr) Variant(variant);
}
static void DestructVariant(Variant* ptr)
{
ptr->~Variant();
}
class VariantMap
{
public:
Variant& operator [] (const ShortStringHash& key) { return data; }
Variant data;
};
static void ConstructVariantMap(VariantMap* ptr)
{
new(ptr) VariantMap();
}
static void ConstructVariantMapCopy(const VariantMap& map, VariantMap* ptr)
{
new(ptr) VariantMap(map);
}
static void DestructVariantMap(VariantMap* ptr)
{
ptr->~VariantMap();
}
static Variant& VariantMapAt(const String& key, VariantMap& map)
{
return map[key];
}
static Variant& VariantMapAtHash(ShortStringHash key, VariantMap& map)
{
return map[key];
}
static CScriptArray* VariantMapGetKeys(const VariantMap& map)
{
return 0;
}
class UIElement
{
public:
void AddRef() {}
void ReleaseRef() {}
VariantMap vars;
};
static VariantMap& UIElementGetVars(UIElement* ptr)
{
return const_cast<VariantMap&>(ptr->vars);
}
static String GetVariableName(const ShortStringHash& key)
{
return String();
}
void MessageCallback(const asSMessageInfo* msg)
{
printf("%s:%d,%d %s\n", msg->section, msg->row, msg->col, msg->message);
}
int main(int argc, char** argv)
{
asIScriptEngine* engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->SetEngineProperty(asEP_USE_CHARACTER_LITERALS, true);
engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, true);
engine->SetEngineProperty(asEP_ALLOW_IMPLICIT_HANDLE_TYPES, true);
engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, true);
engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
engine->RegisterObjectType("Array<class T>", 0, asOBJ_REF | asOBJ_TEMPLATE);
engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_FACTORY, "Array<T>@ f(int& in)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*), CScriptArray*), asCALL_CDECL);
engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_FACTORY, "Array<T>@ f(int& in, uint)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL);
engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_FACTORY, "Array<T>@ f(int& in, uint, const T& in)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT, void *), CScriptArray*), asCALL_CDECL);
engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_LIST_FACTORY, "Array<T>@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, void*), CScriptArray*), asCALL_CDECL);
engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL);
engine->RegisterObjectBehaviour("Array<T>", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL);
engine->RegisterObjectMethod("Array<T>", "Array<T>& opAssign(const Array<T>& in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL);
engine->RegisterObjectMethod("Array<T>", "T& opIndex(uint)", asMETHODPR(CScriptArray, At, (unsigned), void*), asCALL_THISCALL);
engine->RegisterObjectMethod("Array<T>", "const T& opIndex(uint) const", asMETHODPR(CScriptArray, At, (unsigned), void*), asCALL_THISCALL);
engine->RegisterObjectMethod("Array<T>", "uint get_length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL);
engine->RegisterObjectType("String", sizeof(String), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK);
engine->RegisterStringFactory("String", asFUNCTION(StringFactory), asCALL_CDECL);
engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("String", asBEHAVE_CONSTRUCT, "void f(const String&in)", asFUNCTION(ConstructStringCopy), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("String", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("String", "String& opAssign(const String&in)", asMETHODPR(String, operator =, (const String&), String&), asCALL_THISCALL);
engine->RegisterObjectMethod("String", "bool get_empty() const", asMETHOD(String, Empty), asCALL_THISCALL);
engine->RegisterObjectType("ShortStringHash", sizeof(ShortStringHash), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK);
engine->RegisterObjectBehaviour("ShortStringHash", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructShortStringHash), asCALL_CDECL_OBJLAST);
engine->RegisterObjectType("Variant", sizeof(Variant), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK);
engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructVariant), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("Variant", asBEHAVE_CONSTRUCT, "void f(const Variant&in)", asFUNCTION(ConstructVariantCopy), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("Variant", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructVariant), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("Variant", "Variant& opAssign(const Variant&in)", asMETHODPR(Variant, operator =, (const Variant&), Variant&), asCALL_THISCALL);
engine->RegisterObjectType("VariantMap", sizeof(VariantMap), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK);
engine->RegisterObjectBehaviour("VariantMap", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructVariantMap), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("VariantMap", asBEHAVE_CONSTRUCT, "void f(const VariantMap&in)", asFUNCTION(ConstructVariantMapCopy), asCALL_CDECL_OBJLAST);
engine->RegisterObjectBehaviour("VariantMap", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructVariantMap), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("VariantMap", "Array<ShortStringHash>@ get_keys() const", asFUNCTION(VariantMapGetKeys), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("VariantMap", "Variant& opIndex(const String&in)", asFUNCTION(VariantMapAt), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("VariantMap", "const Variant& opIndex(const String&in) const", asFUNCTION(VariantMapAt), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("VariantMap", "Variant& opIndex(ShortStringHash)", asFUNCTION(VariantMapAtHash), asCALL_CDECL_OBJLAST);
engine->RegisterObjectMethod("VariantMap", "const Variant& opIndex(ShortStringHash) const", asFUNCTION(VariantMapAtHash), asCALL_CDECL_OBJLAST);
engine->RegisterObjectType("UIElement", 0, asOBJ_REF);
engine->RegisterObjectBehaviour("UIElement", asBEHAVE_ADDREF, "void f()", asMETHODPR(UIElement, AddRef, (), void), asCALL_THISCALL);
engine->RegisterObjectBehaviour("UIElement", asBEHAVE_RELEASE, "void f()", asMETHODPR(UIElement, ReleaseRef, (), void), asCALL_THISCALL);
engine->RegisterObjectMethod("UIElement", "VariantMap& get_vars()", asFUNCTION(UIElementGetVars), asCALL_CDECL_OBJLAST);
engine->RegisterGlobalFunction("String GetVariableName(const ShortStringHash&in)", asFUNCTION(GetVariableName), asCALL_CDECL);
asIScriptModule* module = engine->GetModule("Test", asGM_ALWAYS_CREATE);
string script =
"UIElement@ element;\n"
"VariantMap internalVars;\n"
"void Test()\n"
"{\n"
" Array<ShortStringHash> keys = element.vars.keys;\n"
" for (uint i = 0; i < keys.length; ++i)\n"
" {\n"
" String name = GetVariableName(keys[i]);\n"
" if (name.empty)\n"
" internalVars[keys[i]] = element.vars[keys[i]];\n"
" }\n"
"}\n\n";
printf("%s", script.c_str());
module->AddScriptSection("Test", script.c_str());
module->Build();
return 0;
}