Wrong bytecode with funcdef in shared interface

Started by
9 comments, last by cvet 9 years, 11 months ago

Hello.

AngelScript revision 1923.

How to reproduce:

module->SaveByteCode(...); -> ok

module->LoadByteCode(...); -> first restore is ok

module->SaveByteCode(...); -> give different output compare to first call of SaveByteCode (very small difference, about 6 bytes on 10kb)

module->LoadByteCode(...); -> error in ReadUsedFunctions on line 622

Code must be something like it:

funcdef void CALLBACK();

shared interface A

{

void Func(CALLBACK@ callback);

}

class B : A

{

void Func(CALLBACK@ callback){}

}

If this not help than i try localize problem more precisely.

Advertisement

Thanks. I'll try to reproduce the problem with this information.

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

Unfortunately it was not enough. I tried the following:

// Test repeated save/loads with shared interfaces and funcdefs
// http://www.gamedev.net/topic/656784-wrong-bytecode-with-funcdef-in-shared-interface/
{
  engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
  engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
 
  mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
  mod->AddScriptSection("test",
    "funcdef void CALLBACK(); \n"
    "shared interface A \n"
    "{ \n"
    "    void Func(CALLBACK@ callback); \n"
    "} \n"
    "class B : A \n"
    "{ \n"
    "    void Func(CALLBACK@ callback){} \n"
    "} \n");
  r = mod->Build();
  if( r < 0 )
    TEST_FAILED;
 
  CBytecodeStream stream(__FILE__"shared");
  r = mod->SaveByteCode(&stream);
  if( r < 0 )
    TEST_FAILED;
 
  asDWORD crc1 = ComputeCRC32(&stream.buffer[0], asUINT(stream.buffer.size()));
 
  r = mod->LoadByteCode(&stream);
  if( r < 0 )
    TEST_FAILED;
 
  CBytecodeStream stream2(__FILE__"shared2");
  r = mod->SaveByteCode(&stream2);
  if( r < 0 )
    TEST_FAILED;
 
  asDWORD crc2 = ComputeCRC32(&stream2.buffer[0], asUINT(stream2.buffer.size()));
 
  if( crc1 != crc2 )
    TEST_FAILED;
 
  r = mod->LoadByteCode(&stream2);
  if( r < 0 )
    TEST_FAILED;
 
  engine->Release();
}

I also tried loading the bytecode into a different module, or even a different engine, but none of the tests reproduced the problem.

If you can figure out in what part of asCWriter that the output is different in the second save, it might help me understand exactly what is causing it.

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

If i attach this two different binary files this help?

I localize problem to this:

Module1:

funcdef void CALLBACK();

Module2:

funcdef void CALLBACK();
void Foo1(CALLBACK@){}
void Foo2(){Foo1(null);}

Steps:

Module1 load from code

Module2 load from code

Module1->SaveByteCode

Module2->SaveByteCode

Module1->LoadByteCode

Module2->LoadByteCode

Module1->SaveByteCode

Module2->SaveByteCode -> give different output

Module1->LoadByteCode

Module2->LoadByteCode -> give error

Still, no luck.

I updated the test with like this:

// Test repeated save/loads with shared interfaces and funcdefs
// http://www.gamedev.net/topic/656784-wrong-bytecode-with-funcdef-in-shared-interface/
{
  engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
  engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
 
  asIScriptModule *mod1 = engine->GetModule(0, asGM_ALWAYS_CREATE);
  mod1->AddScriptSection("test",
    "funcdef void CALLBACK(); \n");
  r = mod1->Build();
  if( r < 0 )
    TEST_FAILED;
 
  asIScriptModule *mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
  mod2->AddScriptSection("test",
    "funcdef void CALLBACK(); \n"
    "void Foo1(CALLBACK@){} \n"
    "void Foo2(){Foo1(null);} \n");
  r = mod2->Build();
  if( r < 0 )
    TEST_FAILED;
 
  CBytecodeStream stream1(__FILE__"shared1");
  r = mod1->SaveByteCode(&stream1);
  if( r < 0 )
    TEST_FAILED;
 
  CBytecodeStream stream2(__FILE__"shared2");
  r = mod2->SaveByteCode(&stream2);
  if( r < 0 )
    TEST_FAILED;
 
  asDWORD crc1 = ComputeCRC32(&stream2.buffer[0], asUINT(stream2.buffer.size()));
 
  r = mod1->LoadByteCode(&stream1);
  if( r < 0 )
    TEST_FAILED;
 
  r = mod2->LoadByteCode(&stream2);
  if( r < 0 )
    TEST_FAILED;
 
  CBytecodeStream stream3(__FILE__"shared1");
  r = mod1->SaveByteCode(&stream3);
  if( r < 0 )
    TEST_FAILED;
 
  CBytecodeStream stream4(__FILE__"shared2");
  r = mod2->SaveByteCode(&stream4);
  if( r < 0 )
    TEST_FAILED;
 
  asDWORD crc2 = ComputeCRC32(&stream4.buffer[0], asUINT(stream4.buffer.size()));
 
  if( crc1 != crc2 )
    TEST_FAILED;
 
  r = mod1->LoadByteCode(&stream3);
  if( r < 0 )
    TEST_FAILED;
 
  r = mod2->LoadByteCode(&stream4);
  if( r < 0 )
    TEST_FAILED;
 
  engine->Release();
}

Unfortunately the test still doesn't reproduce the problem.

Perhaps to reproduce it something specific needs to be registered with the engine too?

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 test case must reproduce problem:




bool Test()
{
	bool fail = false;
	int r;
	COutStream out;
	asIScriptModule *mod1, *mod2;
	asIScriptEngine *engine;

	CBytecodeStream stream1(__FILE__"shared1");
	CBytecodeStream stream2(__FILE__"shared2");
	CBytecodeStream stream3(__FILE__"shared3");
	CBytecodeStream stream4(__FILE__"shared4");

	asDWORD crc1, crc2;

	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		mod1 = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod1->AddScriptSection("test",
			"funcdef void CALLBACK();\n");
		r = mod1->Build();
		if( r < 0 )
			TEST_FAILED;
		mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod2->AddScriptSection("test",
			"funcdef void CALLBACK(); \n"
			"void Foo1(CALLBACK@){} \n"
			"void Foo2(){Foo1(null);}\n");
		r = mod2->Build();
		if( r < 0 )
			TEST_FAILED;

		r = mod1->SaveByteCode(&stream1);
		if( r < 0 )
			TEST_FAILED;
		r = mod2->SaveByteCode(&stream2);
		if( r < 0 )
			TEST_FAILED;

		crc1 = ComputeCRC32(&stream2.buffer[0], asUINT(stream2.buffer.size()));

		engine->Release();
	}

	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		mod1 = engine->GetModule(0, asGM_ALWAYS_CREATE);
		r = mod1->LoadByteCode(&stream1);
		if( r < 0 )
			TEST_FAILED;
		mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
		r = mod2->LoadByteCode(&stream2);
		if( r < 0 )
			TEST_FAILED;

		r = mod1->SaveByteCode(&stream3);
		if( r < 0 )
			TEST_FAILED;
		r = mod2->SaveByteCode(&stream4);
		if( r < 0 )
			TEST_FAILED;

		crc2 = ComputeCRC32(&stream4.buffer[0], asUINT(stream4.buffer.size()));
		if( crc1 != crc2 )
			TEST_FAILED;

		engine->Release();
	}

	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		mod1 = engine->GetModule(0, asGM_ALWAYS_CREATE);
		r = mod1->LoadByteCode(&stream3);
		if( r < 0 )
			TEST_FAILED;
		mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
		r = mod2->LoadByteCode(&stream4);
		if( r < 0 )
			TEST_FAILED;

		engine->Release();
	}

	// Success
	return fail;
}

Ah, so there was a need to create new engine instances as well.

OK. I'll give it a try tonight.

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

Yes, now I'm able to reproduce the error. I'll let you know as soon as I have a fix available.

Thanks for the help so far.

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 problem in revision 1931.

The problem was when loading the bytecode with the funcdef. The funcdef was incorrectly marked as owned by the module. This is what caused the bytecode to be saved slightly differently in the second iteration and ultimately why the bytecode failed to load again.

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

This topic is closed to new replies.

Advertisement