Sign in to follow this  
AgentC

tempVariables assertion with indexed unsafe reference

Recommended Posts

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 smile.png

 

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;
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this