Debug problems

Started by
20 comments, last by WitchLord 19 years, 7 months ago
Ok, all is good now. Apparently my app didnt appriciate me compiling AS using the Multithreaded DLL runtime library. Had to use the Multithreaded runtime library to get it to work. The ?: operator seems to be working, but I'll keep trying to break it...
Advertisement
hehe [smile]

I'm glad it is fixed. I'm not sure which of the changes it was that corrected the problem though, but I suppose it doesn't matter.

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

Ok, I have my head on straight now. Ignore those other posts. :) I seemed to forgot what my own problem was: running in debug mode without assertions killing my app. Well, when I tested the stuff earlier, I was running in release mode (duh).

I tried stuff out in debug mode; oh boy.

1. The original problem still exists:
//Assertion failed: n < destructors.GetLength(), file d:\code\angelscript_1_9_1_wip1\source\as_bytecode.cpp, line 420bool cur = this->TestFlag(mode, "true");this->SetAttributeBase(mode, cur ? "false" : "true");send(cur ? disable : enable);// Both functions expect string params

2. I've had to remove every instance of ?: from my scripts to stop the assertions from tripping. Here is an example of what used to work, but doesnt anymore:
//Assertion failed: !bc || bc->GetLastCode() == BC_SET4, file d:\code\angelscript_1_9_1_wip1\source\as_compiler.cpp, line 1945Data* pExit = refid != 0 ? Dataset[refid] : 0;// refid is uint// Dataset[refid] returns Data*

3. A new problem which I still don't understand:
for (iterator i = users.Begin(); i != users.End(); i.Next()){	//Assertion failed: from->isConstant || from->dataType.IsPrimitive(), file d:\code\angelscript_1_9_1_wip1\source\as_compiler.cpp, line 1810	TX.Set("user", i.Value());	user_channel = get_integer_base(i.Value(), "broadcast");	if (user_channel == channel && user_channel != 0)		send("txt_broadcast_join_notify", i.Value(), this);	else if (user_channel == oldchannel && user_channel != 0)		send("txt_broadcast_join_left", i.Value(), this);}// TX is a global property// i.Value() returns Data*


Oddly enough, if I change the above to the following, it compiles ok:

for (iterator i = users.Begin(); i != users.End(); i.Next()){	TX.Set("user", 0);	user_channel = get_integer_base(i.Value(), "broadcast");	if (user_channel == channel && user_channel != 0)		send("txt_broadcast_join_notify", i.Value(), this);	else if (user_channel == oldchannel && user_channel != 0)		send("txt_broadcast_join_left", i.Value(), this);}


This works too:

for (iterator i = users.Begin(); i != users.End(); i.Next()){	Data* temp = i.Value();	TX.Set("user", temp);	user_channel = get_integer_base(i.Value(), "broadcast");	if (user_channel == channel && user_channel != 0)		send("txt_broadcast_join_notify", i.Value(), this);	else if (user_channel == oldchannel && user_channel != 0)		send("txt_broadcast_join_left", i.Value(), this);}


Strange indeed...
Very strange indeed.

Ok, at least I have something to go on. I'll try to reproduce the problems exactly as you write them.

Do you register any behaviours for the Data type? It shouldn't really make a difference since you're only using a pointer to the type, but I might have made an error.

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'm closing in on the problems:

1. These are the test cases that I've identified to have problems
 // This compiles, but it fails to release the memorystring a = true ? "true" : "false";SetAttrib(a);// This gives an assert failure in GenerateExceptionHandler()SetAttrib(true ? "true" : "false");// This gives an assert failure in GenerateExceptionHandler()string f = "false", t = "true";SetAttrib(true ? f : t);


2. I've confirmed the bug

3. I'm not able to reproduce this problem. Could you tell me how you registered the methods TX.Set() and i.Value(). I need to know the parameters you sent to RegisterObjectMethod() for these two.

The first two problems should be fixed soon. I'll need your help before I can fix the third one.

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

The problems I am experiencing only creep up during debug builds.

Users cannot create variables of by CStringTransform in the scripts. Instead, they share one global instance (TX):

pEngine->RegisterObjectType("CStringTransform", 0, asOBJ_CLASS);pEngine->RegisterObjectMethod("CStringTransform", "void Clear()", asMETHOD(CStringTransform, Clear), asCALL_THISCALL);pEngine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, Data* pData)", asMETHODP(CStringTransform, Set, (const string&, CData*)), asCALL_THISCALL);pEngine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, const string& value)", asMETHODP(CStringTransform, Set, (const string&, const string&)), asCALL_THISCALL);pEngine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, int i)", asMETHODP(CStringTransform, Set, (const string&, int)), asCALL_THISCALL);pEngine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, float f)", asMETHODP(CStringTransform, Set, (const string&, float)), asCALL_THISCALL);pEngine->RegisterObjectMethod("CStringTransform", "string Transform(const string& buffer)", asMETHOD(CStringTransform, Transform), asCALL_THISCALL);m_pEngine->RegisterGlobalProperty("CStringTransform TX", &m_Transform);


This bunch is messy, but here is the iterator:

pEngine->RegisterObjectBehaviour("list", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(list_ctor), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectBehaviour("list", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(list_dtor), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectMethod("list", "int Size()", asMETHOD(list<CData*>, size), asCALL_THISCALL);pEngine->RegisterObjectMethod("list", "void Filter(const string& type)", asFUNCTION(list_filter), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectMethod("list", "void Clear()", asMETHOD(list<CData*>, clear), asCALL_THISCALL);pEngine->RegisterObjectMethod("list", "iterator Erase(iterator i)", asMETHODPR(list<CData*>, erase, (list<CData*>::iterator), list<CData*>::iterator), asCALL_THISCALL);pEngine->RegisterObjectMethod("list", "iterator Begin()", asMETHODPR(list<CData*>, begin, (), list<CData*>::iterator), asCALL_THISCALL);pEngine->RegisterObjectMethod("list", "iterator End()", asMETHODPR(list<CData*>, end, (), list<CData*>::iterator), asCALL_THISCALL);pEngine->RegisterObjectMethod("iterator", "Data* Value()", asFUNCTION(iterator_deref), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectMethod("iterator", "iterator& Next()", asFUNCTION(iterator_next), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectMethod("iterator", "iterator& Prev()", asFUNCTION(iterator_previous), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectBehaviour("iterator", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(iterator_ctor), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectBehaviour("iterator", asBEHAVE_ASSIGNMENT, "iterator& f(const iterator&)", asFUNCTION(iterator_assign_iterator), asCALL_CDECL_OBJLAST);pEngine->RegisterObjectBehaviour(0, asBEHAVE_EQUAL, "bool f(const iterator&, const iterator&)", asFUNCTION(iterator_equal_iterator), asCALL_CDECL);pEngine->RegisterObjectBehaviour(0, asBEHAVE_NOTEQUAL, "bool f(const iterator&, const iterator&)", asFUNCTION(iterator_not_equal_iterator), asCALL_CDECL);


And here are the glue functions:

void iterator_ctor(list<CData*>::iterator *pthis){	new(pthis)list<CData*>::iterator();}list<CData*>::iterator& iterator_assign_iterator(const list<CData*>::iterator &copy, list<CData*>::iterator *pthis){	return *pthis = copy;}CData* iterator_deref(list<CData*>::iterator* pthis){	return **pthis;}list<CData*>::iterator& iterator_next(list<CData*>::iterator* pthis){	(*pthis)++;	return *pthis;}list<CData*>::iterator& iterator_previous(list<CData*>::iterator* pthis){	(*pthis)--;	return *pthis;}bool iterator_equal_iterator(const list<CData*>::iterator& l, const list<CData*>::iterator& r){	return l == r;}bool iterator_not_equal_iterator(const list<CData*>::iterator& l, const list<CData*>::iterator& r){	return l != r;}


fyi, I actually have my current project posted at:

http://members.gamedev.net/ajwright/lands/downloads/landsdev7.zip

Although, I am using VS.NET 2003. If you are using VS6 then I don't think this will compile (differences in the STLs).
I believe the first two problems have been fixed.

Replace the implementation for the asCCompiler::CompileCondition()

void asCCompiler::CompileCondition(asCScriptNode *expr, asCByteCode *bc, sTypeInfo *type){	sTypeInfo ctype, rtype, ltype;	// Compile the conditional expression	asCScriptNode *cexpr = expr->firstChild;	if( cexpr->next )	{		asCByteCode ebc;		CompileExpression(cexpr, &ebc, &ctype);		PrepareOperand(&ctype, &ebc, cexpr);		if( ctype.dataType != asCDataType(ttBool, true, false) )			Error(TXT_EXPR_MUST_BE_BOOL, cexpr);		int afterLabel = nextLabel++;		int elseLabel = nextLabel++;		ebc.InstrINT(BC_JZ, elseLabel);		asCByteCode lebc;		CompileAssignment(cexpr->next, &lebc, &ltype);		// Allocate temporary variable and copy the result to that one		sTypeInfo temp;		temp = ltype;		temp.dataType.isReference = false;		temp.dataType.isReadOnly = false;		int offset = AllocateVariable(temp.dataType, true);		temp.isTemporary = true;		temp.stackOffset = (short)offset;		CompileConstructor(temp.dataType, offset, bc);		bc->AddCode(&ebc);		sTypeInfo rtemp;		rtemp = temp;		rtemp.dataType.isReference = true;		PrepareForAssignment(&rtemp.dataType, &ltype, &lebc, cexpr->next);		lebc.InstrWORD(BC_PSF, offset);		PerformAssignment(&rtemp, &lebc, cexpr->next);		lebc.Pop(ltype.dataType.GetSizeOnStackDWords()); // Pop the original value		// Release the old temporary variable		ReleaseTemporaryVariable(ltype, &lebc);		bc->AddCode(&lebc);		bc->InstrINT(BC_JMP, afterLabel);		bc->Label((short)elseLabel);		asCByteCode rebc;		CompileAssignment(cexpr->next->next, &rebc, &rtype);		// Copy the result to the same temporary variable		PrepareForAssignment(&rtemp.dataType, &rtype, &rebc, cexpr->next);		rebc.InstrWORD(BC_PSF, offset);		PerformAssignment(&rtemp, &rebc, cexpr->next);		rebc.Pop(ltype.dataType.GetSizeOnStackDWords()); // Pop the original value		// Release the old temporary variable		ReleaseTemporaryVariable(rtype, &rebc);		bc->AddCode(&rebc);		bc->Label((short)afterLabel);		bc->InstrWORD(BC_PSF, offset);		// Make sure both expressions have the same type		if( ltype.dataType != rtype.dataType )			Error(TXT_BOTH_MUST_BE_SAME, expr);		// Set the temporary variable as output		*type = rtemp;	}	else		CompileExpression(cexpr, bc, type);}


Insert the following line in function ImplicitConversionConstant() (as_compiler.cpp, ln: 1874)

from->dataType.isReadOnly = true;


Should look like this:

	// Only 0 can be implicitly converted to a pointer	if( to.pointerLevel > 0 )	{		asCDataType temp = asCDataType(ttInt, true, false);		ImplicitConversion(bc, temp, from, node, isExplicit);		if( from->dataType.IsIntegerType() && from->dwordValue == 0 )		{			// Copy all except isReference			from->dataType = to;			from->dataType.isReference = false;			from->dataType.isReadOnly = true;			return;		}	}


I will see if I can reproduce the third problem with the extra information you gave me.

I received VC++.NET 2003 as donation to AngelCode, but I haven't had the time to try it out yet.

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 still can't reproduce the third problem you reported. I created the following test:

#include "utils.h"#include "stdstr.h"#define TESTNAME "TestAsserts"static const char *script1 ="void Test()                               \n""{                                         \n""  Obj i;                                  \n""  TX.Set(\"user\", i.Value());            \n""}                                         \n";class Obj{public:	void *p;	void *Value() {return p;}	void Set(const std::string&, void *) {}};static Obj o;bool TestAsserts(){	bool fail = false;	int r;	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);	RegisterStdString(engine);	engine->RegisterObjectType("Data", 0, 0);	engine->RegisterObjectType("Obj", sizeof(Obj), 0);	engine->RegisterObjectMethod("Obj", "Data *Value()", asMETHOD(Obj, Value), asCALL_THISCALL);	engine->RegisterObjectMethod("Obj", "void Set(const string&, Data *)", asMETHOD(Obj, Set), asCALL_THISCALL);	engine->RegisterGlobalProperty("Obj TX", &o);	COutStream out;		engine->AddScriptSection(0, TESTNAME, script1, strlen(script1), 0);	engine->Build(0, &out);	r = engine->ExecuteString(0, "Test()", &out, 0);	if( r < 0 )	{		fail = true;		printf("%s: ExecuteString() failed\n", TESTNAME);	}	engine->Release();	// Success	return fail;}


Which ought to reproduce the problem as the methods called are registered with the exact same signatures as in your application.

Can you make a test with the above code and see if it causes the same problem with your compiler?

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 posted this test case at http://members.gamedev.net/ajwright/temp/astest1.zip; the project files are .NET, but it should compile under 6.0

Leaving these lines as-is causes the assertion:
r = engine->RegisterObjectType("CStringTransform", 0, asOBJ_CLASS);r = engine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, Data* pData)", asMETHODP(CStringTransform, Set, (const string&, CData*)), asCALL_THISCALL);r = engine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, const string& value)", asMETHODP(CStringTransform, Set, (const string&, const string&)), asCALL_THISCALL);//r = engine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, int i)", asMETHODP(CStringTransform, Set, (const string&, int)), asCALL_THISCALL);


Changing the comment around causing the assertion to go away:
r = engine->RegisterObjectType("CStringTransform", 0, asOBJ_CLASS);r = engine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, Data* pData)", asMETHODP(CStringTransform, Set, (const string&, CData*)), asCALL_THISCALL);//r = engine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, const string& value)", asMETHODP(CStringTransform, Set, (const string&, const string&)), asCALL_THISCALL);r = engine->RegisterObjectMethod("CStringTransform", "void Set(const string& tag, int i)", asMETHODP(CStringTransform, Set, (const string&, int)), asCALL_THISCALL);

(It still crashes, but that is to be expected- it is dereferencing an invalid stl iterator.)

This topic is closed to new replies.

Advertisement