Weird crash in userFree on Android

Started by
2 comments, last by WitchLord 8 years, 9 months ago

I'm experiencing a crash when calling native functions from script, which are precompiled by the way.

This is the function causing all of the trouble:


r = pEngine->RegisterGlobalFunction( "void DrawSprite( int,int,PointF)", asMETHOD(Renderer, DrawSprite), asCALL_THISCALL_ASGLOBAL, pGm->GetRenderer()); assert(r >= 0);

PointF is defined like so:


class PointF
{
public:
    PointF();
    PointF( float _x, float _y);
    PointF( const PointF &other);

    void Set( float _x, float _y);
    void SetX(float _x);
    void SetY(float _y);

    float GetX();
    float GetY();

private:
    float x, y;
};

void ConstructorDefaultPointF( PointF *m);
void ConstructorInitPointF( float x, float y, PointF *m);
void ConstructorCopyPointF( const PointF &other, PointF *m);
void DestructorPointF( PointF *m);

//PointF
	r = pEngine->RegisterObjectType("PointF", sizeof(PointF), asOBJ_VALUE|asOBJ_POD|asGetTypeTraits<PointF>()); assert( r >= 0);
	r = pEngine->RegisterObjectBehaviour( "PointF", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructorDefaultPointF), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pEngine->RegisterObjectBehaviour( "PointF", asBEHAVE_CONSTRUCT, "void f(float,float)", asFUNCTION(ConstructorInitPointF), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pEngine->RegisterObjectBehaviour( "PointF", asBEHAVE_CONSTRUCT, "void f(const PointF &in)", asFUNCTION(ConstructorCopyPointF), asCALL_CDECL_OBJLAST); assert( r >= 0);
	r = pEngine->RegisterObjectBehaviour( "PointF", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructorPointF), asCALL_CDECL_OBJLAST); assert( r >= 0);

	r = pEngine->RegisterObjectMethod( "PointF", "void Set(float,float)", asMETHOD( PointF, Set), asCALL_THISCALL); assert( r >= 0);
	r = pEngine->RegisterObjectMethod( "PointF", "void SetX(float)", asMETHOD( PointF, SetX), asCALL_THISCALL); assert( r >= 0);
	r = pEngine->RegisterObjectMethod( "PointF", "void SetY(float)", asMETHOD( PointF, SetY), asCALL_THISCALL); assert( r >= 0);

	r = pEngine->RegisterObjectMethod( "PointF", "float GetX()", asMETHOD( PointF, GetX), asCALL_THISCALL); assert( r >= 0);
	r = pEngine->RegisterObjectMethod( "PointF", "float GetY()", asMETHOD( PointF, GetY), asCALL_THISCALL); assert( r >= 0);

DrawSprite is only being called once per frame so far and works for the first 2 frames, but then the app crashes here:

as_scriptengine.cpp


void asCScriptEngine::CallFree(void *obj) const
{
#ifndef WIP_16BYTE_ALIGN
	userFree(obj); <----------------- Crashes in the free function of libc
#else
	userFreeAligned(obj);
#endif
}

Upon examining the problem further, addr points to a pointer holding a strange address, like 0x0000c000 or something

as_callfunc.cpp


// Clean up arguments
	const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
	if( cleanCount )
	{
		args = context->m_regs.stackPointer;

		// Skip the hidden argument for the return pointer
		if( descr->DoesReturnOnStack() )
			args += AS_PTR_SIZE;

		// Skip the object pointer
		if( callConv >= ICC_THISCALL )
			args += AS_PTR_SIZE;

		asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
		for( asUINT n = 0; n < cleanCount; n++, clean++ )
		{
			void **addr = (void**)&args[clean->off];
			if( clean->op == 0 )
			{
				if( *addr != 0 )
				{
					engine->CallObjectMethod(*addr, clean->ot->beh.release);
					*addr = 0;
				}
			}
			else 
			{
				asASSERT( clean->op == 1 || clean->op == 2 );
				asASSERT( *addr );

				if( clean->op == 2 )
					engine->CallObjectMethod(*addr, clean->ot->beh.destruct);
				
				engine->CallFree(*addr);
			}
		}
	}

	return popSize;
} 

The app runs fine if DrawSprite is not called though. What could be causing this?

Advertisement

The code is attempting to free the copy of PointF that is stored on the heap for calling the DrawSprite function.

The problem appears to be that the args pointer is incorrectly incremented with this condition (line 834 in as_callfunc.cpp):


// Skip the object pointer
if( callConv >= ICC_THISCALL )
  args += AS_PTR_SIZE;

This shouldn't be done when object pointer is not on the stack. Try modifying the code like this:

// Skip the object pointer on the stack
if( callConv >= ICC_THISCALL && sysFunc->objForThiscall == 0 )
  args += AS_PTR_SIZE;

I will also try to reproduce this. Is your Android environment running on ARM, or is it another processor?

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's running on ARM, ARMv7 on a HTC One M8 to be specific.

Edit:

The changes work like a charm! Thanks.

The problem and solution was indeed what I imagined earlier.

I reproduced the problem both on Win64 and Android/ARM, and the fixed solved it on both platforms.

The fix is available in the SVN, revision 2200.

Thanks for providing all the details in the bug report to make it easy to identify the cause.

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