Jump to content
  • Advertisement
Sign in to follow this  
ic0de

odd behavior with globally declared scoped reference types, is this normal?

This topic is 1511 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

 

I've was having a little trouble with aligned data types so I tried using scoped reference types to represent these in angelscript. While they seem to work pretty well for managing aligned data I've noticed some funny behavior when they are declared in the global scope. Specifically When I try to access them from the script it causes my application to crash, not the script but my application. So here is an example of this behavior:
 

vec pos = vec(-74.25679016113281f, 0.0f, 27.4027156829834f); //this is a scoped reference type

void loop()
{	
	if(playerInSphere(pos, 25)) //it crashes where I access pos
	{
		//do stuff
	}
}

My guess is that the engine is somehow erroneously determining that 'pos' is out of scope and deleting it so that it ends up passing my application a null pointer which it tries to access and then crashes. Of course I could be wrong, I may have registered the type incorrectly or misunderstood the use of scoped reference types. Does anyone know what might be causing this or is it normal?

Edited by ic0de

Share this post


Link to post
Share on other sites
Advertisement

It is likely a bug in AngelScript with regards to scoped reference types.

 

Can you show me how you've registered the vec type so I can more easily reproduce the same problem and investigate the cause of the crash?

Share this post


Link to post
Share on other sites
Well it's real ugly but here it is, I'm using extensive macros and lambdas so I can declare wrapper functions inline and I apologize for the messiness. The crash still happens without the lambda approach.
 
//these do lambda magic to allow the definition of wrappers inline
#define WRAPFUNC(ret, args, body) asFUNCTION(static_cast<ret(*)args>([]args -> ret body))
#define WRAPEXPR(ret, args, expr) WRAPFUNC(ret, args, {return expr;})

void registerVec()
{
	r = engine->RegisterObjectType("vec", 0, asOBJ_REF | asOBJ_SCOPED); assert(r >= 0);

	r = engine->RegisterObjectBehaviour("vec", asBEHAVE_FACTORY, "vec @f()",				WRAPEXPR(vec*, (),			new vec()),		asCALL_CDECL);		assert(r >= 0);
	r = engine->RegisterObjectBehaviour("vec", asBEHAVE_FACTORY, "vec @f(const vec &in v)",			WRAPEXPR(vec*, (const vec &o),		new vec(o)),		asCALL_CDECL);		assert(r >= 0);
	r = engine->RegisterObjectBehaviour("vec", asBEHAVE_FACTORY, "vec @f(float nx, float nx, float nz)",	WRAPEXPR(vec*, (float x, float y, float z), new vec(x, y, z)),	asCALL_CDECL);		assert(r >= 0);
	r = engine->RegisterObjectBehaviour("vec", asBEHAVE_FACTORY, "vec @f(float n)",				WRAPEXPR(vec*, (float n),		new vec(n)),		asCALL_CDECL);		assert(r >= 0);
	r = engine->RegisterObjectBehaviour("vec", asBEHAVE_RELEASE, "void f()",				WRAPFUNC(void, (vec* t), {if(t)		{ delete t; }}),	asCALL_CDECL_OBJLAST);	assert(r >= 0);

	r = engine->RegisterObjectMethod("vec", "vec &opAssign(const vec &in v)",	asMETHODPR(vec, operator =, (const vec&), vec&), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectMethod("vec", "vec &opMulAssign(const float)",	asMETHODPR(vec, operator *=, (const float), vec&), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("vec", "vec &opDivAssign(const float)",	asMETHODPR(vec, operator /=, (const float), vec&), asCALL_THISCALL); assert( r >= 0 );
	
	r = engine->RegisterObjectMethod("vec", "vec @opDiv(const float) const",	WRAPEXPR(vec*, (float o, vec* v), new vec(*v / o)), asCALL_CDECL_OBJLAST); assert(r >= 0);
	
	r = engine->RegisterObjectMethod("vec", "vec @opMul(const float) const",	WRAPEXPR(vec*, (float o, vec* v), new vec(*v * o)), asCALL_CDECL_OBJLAST); assert(r >= 0);

	r = engine->RegisterObjectMethod("vec", "bool opEquals(const vec &in v) const", asMETHODPR(vec, operator==, (const vec &) const, bool), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectMethod("vec", "vec &opAddAssign(const vec &in v)", asMETHODPR(vec, operator +=, (const vec&), vec&), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("vec", "vec &opSubAssign(const vec &in v)", asMETHODPR(vec, operator -=, (const vec&), vec&), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("vec", "vec &opMulAssign(const vec &in v)", asMETHODPR(vec, operator *=, (const vec&), vec&), asCALL_THISCALL); assert( r >= 0 );
	r = engine->RegisterObjectMethod("vec", "vec &opDivAssign(const vec &in v)", asMETHODPR(vec, operator /=, (const vec&), vec&), asCALL_THISCALL); assert( r >= 0 );
	
	r = engine->RegisterObjectMethod("vec", "vec @opDiv(const vec &in) const",	WRAPEXPR(vec*, (const vec &vo, vec* v), new vec(*v / vo)), asCALL_CDECL_OBJLAST); assert(r >= 0);

	r = engine->RegisterObjectMethod("vec", "vec @opMul(const vec &in) const",	WRAPEXPR(vec*, (const vec &vo, vec* v), new vec(*v * vo)), asCALL_CDECL_OBJLAST); assert(r >= 0);
	
	r = engine->RegisterObjectMethod("vec", "vec @opSub(const vec &in) const",	WRAPEXPR(vec*, (const vec &vo, vec* v), new vec(*v - vo)), asCALL_CDECL_OBJLAST); assert(r >= 0);
	
	r = engine->RegisterObjectMethod("vec", "vec @opAdd(const vec &in) const",	WRAPEXPR(vec*, (const vec &vo, vec* v), new vec(*v + vo)), asCALL_CDECL_OBJLAST); assert(r >= 0);

	r = engine->RegisterObjectMethod("vec", "void normalize()",		asMETHOD(vec, normalize), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectMethod("vec", "vec @normalized()",	WRAPEXPR(vec*, (vec* v), new vec(v->normalized())), asCALL_CDECL_OBJLAST); assert(r >= 0);

	r = engine->RegisterObjectMethod("vec", "float magnitude()",	asMETHOD(vec, magnitude), asCALL_THISCALL); assert( r >= 0 );

	r = engine->RegisterObjectProperty("vec", "float x", asOFFSET(vec, x)); assert( r >= 0 );
	r = engine->RegisterObjectProperty("vec", "float y", asOFFSET(vec, y)); assert( r >= 0 );
	r = engine->RegisterObjectProperty("vec", "float z", asOFFSET(vec, z)); assert( r >= 0 );
}
Edited by ic0de

Share this post


Link to post
Share on other sites

It was indeed a bug in the library. I've fixed this in revision 2023.

 

 

Observe, that the new operator is not guaranteed to allocate the memory with the necessary alignment. I assume you're using a __m128 type in your vec class, thus you would need an alignment of 16 bytes. To get the proper alignment you need to use _aligned_malloc to allocate the memory and then the placement new operator to initialize it. The memory must then be freed with _aligned_free.

// Allocate memory with proper alignment then initialize it
r = engine->RegisterObjectBehaviour("vec", asBEHAVE_FACTORY, "vec @f()",  WRAPEXPR(vec*, (), new(_aligned_malloc(sizeof(vec), std::alignment_of<vec>().value)) vec()), asCALL_CDECL); assert(r >= 0);
// Manually call destructor then free the memory
r = engine->RegisterObjectBehaviour("vec", asBEHAVE_RELEASE, "void f()",  WRAPFUNC(void, (vec* t), {if(t) { t->~vec(); _aligned_free(t); }}), asCALL_CDECL_OBJLAST); assert(r >= 0);

Regards,

Andreas

Edited by Andreas Jonsson

Share this post


Link to post
Share on other sites
Thanks for the amazingly quick fix. I know that new isn't guaranteed to be aligned but I overloaded the operator to ensure this as I was having trouble in other parts of application.

EDIT: tested your revision with my code and it works like magic, you really are a wizard. Edited by ic0de

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!