Segfault when casting directly

Started by
5 comments, last by kozec 11 years, 3 months ago

Hi.

I'm trying to use AngelScript as scripting language in my one-day-it-will-be-game and I encountered weird problem today.

I have two registered C++ classes, EventSource and ASConsole derived from it and registered method addListener(EventSource* source, ...)

Now, if I call addListener like this...






ASConsole@ console; // This is actually global variable
void main() {
	EventSource@ s = cast<EventSource>(console);
	module.addListener(s, ET_READLINE, onLine);
	loop();
}

... everything is OK. ASConsole is dynamic_cast-ed to EventSource, pointer is returned and addListener recieves same pointer. But, if I do this...






ASConsole@ console; // This is actually global variable
void main() {
	module.addListener(cast<EventSource>(console), ET_READLINE, onLine);
	loop();
}

... dynamic_cast returns one pointer (0x81a240), addListener recieves something else (0x8c5f98) and entire thing segfaults.

Am I doing something wrong? And, is there possibility to prevent segfault when this wrong method is used? I would like to let users to use some in-game scripting, but I really don't want to let them crash entire thing.

Advertisement
Both ways should be equivalent. It would appear you've encountered a bug in the compiler.

I'll investigate this.

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 wasn't able to reproduce the problem.

Does this code represent well what you have? If not, can you spot what is different?
class EventSource
{
public:
	EventSource() {refCount = 1; value = 42;};
	virtual ~EventSource() {}
	virtual void AddRef() {refCount++;}
	virtual void Release() {if( --refCount == 0 ) delete this;}
	int refCount;

	int value;
};

class ASConsole : public EventSource
{
public:
	static ASConsole *factory() { return new ASConsole(); }
	EventSource *opCast() { return this; }
};

bool Test()
{
	bool fail = false;
	int r;
	asIScriptEngine *engine;

	CBufferedOutStream bout;
	COutStream out;

	// http://www.gamedev.net/topic/636163-segfault-when-casting-directly/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		RegisterStdString(engine);

		engine->RegisterObjectType("EventSource", 0, asOBJ_REF);
		engine->RegisterObjectBehaviour("EventSource", asBEHAVE_ADDREF, "void f()", asMETHOD(EventSource, AddRef), asCALL_THISCALL);
		engine->RegisterObjectBehaviour("EventSource", asBEHAVE_RELEASE, "void f()", asMETHOD(EventSource, Release), asCALL_THISCALL);
		engine->RegisterObjectProperty("EventSource", "int value", asOFFSET(EventSource, value));

		engine->RegisterObjectType("ASConsole", 0, asOBJ_REF);
		engine->RegisterObjectBehaviour("ASConsole", asBEHAVE_FACTORY, "ASConsole @f()", asFUNCTION(ASConsole::factory), asCALL_CDECL);
		engine->RegisterObjectBehaviour("ASConsole", asBEHAVE_ADDREF, "void f()", asMETHOD(ASConsole, AddRef), asCALL_THISCALL);
		engine->RegisterObjectBehaviour("ASConsole", asBEHAVE_RELEASE, "void f()", asMETHOD(ASConsole, Release), asCALL_THISCALL);
		engine->RegisterObjectBehaviour("ASConsole", asBEHAVE_REF_CAST, "EventSource@+ f()", asMETHOD(ASConsole, opCast), asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"enum E { ET_READLINE = 24 } \n"
			"class Module { \n"
			"  void addListener(EventSource @s, E type, string line) {\n"
			"    assert(line == 'test'); \n"
			"    assert(type == ET_READLINE); \n"
			"    assert(s.value == 42); \n"
			"    EventSource @c = cast<EventSource>(console); \n"
			"    assert(c is s); \n"
			"  } \n"
			"} \n"
			"Module module; \n"
			"string onLine = 'test'; \n"
			"ASConsole @console = ASConsole(); \n"
			"void main() \n"
			"{ \n"
			"  module.addListener(cast<EventSource>(console), ET_READLINE, onLine); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

 	return fail;
}

- What version of AngelScript are you using?
- On what OS are you developing your code?
- With what 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

Hello again. I'm sorry for my late response, there were some trouble with my account and I was not able to login.

Andreas, I modified your code a little so now its manifest same problem. Main difference is that my addListener method is in c++, not AS. Here is code and here is zipped eclipse project as well.
When I launch this code, both addListener calls...


EventSource@ x = cast(console);
addListener(x, ET_READLINE);               // source is first parameter
addListener(cast(console), ET_READLINE);   // source is first parameter

... should yield same results. In fact, output is:


ASRefCast: returning 0x940010
addListener: source = 0x940010
addListener: source.value = 2a

ASRefCast: returning 0x940010
addListener: source = 0x956400
addListener: source.value = 0

Value passed from typecasting function to addListener gets somehow changed sad.png

I'm on ArchLinux (3.6.9-1-ARCH), x86_64, using angelscript 2.25.2, built from AUR. As compiler, g++ (from gcc package, version 4.7.2) is used.

Thanks for providing the additional information.

It's possible that this is a 64bit specific bug. I'll try to reproduce it on the 64bit Linux platform I have at my disposal.

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

It turns out the problem wasn't 64bit specific after all.<br /><br />With the code you provided I found the problem. It was related to passing a handle stored in a temporary variable to a function that expected a non-handle inout reference. In this specific case the compiler didn't properly dereference the pointer on the stack so the function ended up receiving a pointer to the handle, rather than the object itself.<br /><br />I've fixed this problem in revision 1522.<br /><br />Thanks for the help in reproducing the problem.

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

Great. Thank you very much for your help :)

This topic is closed to new replies.

Advertisement