Sign in to follow this  
kozec

Segfault when casting directly

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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? Edited by Andreas Jonsson

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
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.

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