Constraints and collisions cause instant crash.

CookieMonster
Posts: 49
Joined: Sun Jan 29, 2012 10:01 pm

Constraints and collisions cause instant crash.

Post by CookieMonster »

Every first time a collision or constraint is applied to a rigid body, there is a 50% chance that the step simulation call crash with access violation. Using dynamic allocations only caused the access violation to happend with a NULL pointer.

Code: Select all

#include <new>
#define STORE_STATIC_MEMORY(CLASSNAME,MEMORY,POINTER) char MEMORY##[sizeof(CLASSNAME)]; CLASSNAME##* POINTER;
#define POINT_TO_STATIC_MEMORY(CLASSNAME,MEMORY,POINTER) POINTER = (CLASSNAME##*)(&##(MEMORY));

struct PhysicsCore {
	STORE_STATIC_MEMORY(btDefaultCollisionConfiguration,collisionConfigurationData,collisionConfiguration)
	STORE_STATIC_MEMORY(btCollisionDispatcher,dispatcherData,dispatcher)
	STORE_STATIC_MEMORY(btDbvtBroadphase,overlappingPairCacheData,overlappingPairCache)
	STORE_STATIC_MEMORY(btSequentialImpulseConstraintSolver,solverData,solver)
	STORE_STATIC_MEMORY(btDiscreteDynamicsWorld,dynamicsWorldData,dynamicsWorld)
};

void Physics_Init(PhysicsCore* Core) {
	// Connect pointers to static data
	POINT_TO_STATIC_MEMORY(btDefaultCollisionConfiguration,Core->collisionConfigurationData,Core->collisionConfiguration)
	POINT_TO_STATIC_MEMORY(btCollisionDispatcher,Core->dispatcherData,Core->dispatcher)
	POINT_TO_STATIC_MEMORY(btDbvtBroadphase,Core->overlappingPairCacheData,Core->overlappingPairCache)
	POINT_TO_STATIC_MEMORY(btSequentialImpulseConstraintSolver,Core->solverData,Core->solver)
	POINT_TO_STATIC_MEMORY(btDiscreteDynamicsWorld,Core->dynamicsWorldData,Core->dynamicsWorld)
	
	// Use placement new for initializing the classes
	Core->collisionConfiguration = new(Core->collisionConfiguration) btDefaultCollisionConfiguration();
	Core->dispatcher = new(Core->dispatcher) btCollisionDispatcher(Core->collisionConfiguration);
	Core->overlappingPairCache = new(Core->overlappingPairCache) btDbvtBroadphase();
	Core->solver = new(Core->solver) btSequentialImpulseConstraintSolver();
	Core->dynamicsWorld = new(Core->dynamicsWorld) btDiscreteDynamicsWorld(Core->dispatcher,Core->overlappingPairCache,Core->solver,Core->collisionConfiguration);
}

void Physics_Terminate(PhysicsCore* Core) {
	// Terminate the classes
	Core->dynamicsWorld-> ~btDiscreteDynamicsWorld();
	Core->solver-> ~btSequentialImpulseConstraintSolver();
	Core->overlappingPairCache-> ~btDbvtBroadphase();
	Core->dispatcher-> ~btCollisionDispatcher();
	Core->collisionConfiguration-> ~btDefaultCollisionConfiguration();
}

struct RigidBody_Struct {
	COLLECTION_STRUCT_DATA(RigidBody)
	STORE_STATIC_MEMORY(btRigidBody,StaticBody,Body)
	CollisionShape_Struct* Shape;
	float LinearMass;
	float AngularMass;
};

RigidBody_Struct* EngineCore::RigidBody_Create(CollisionShape_Struct* Shape, float LinearMass, float AngularMass,float PosX,float PosY,float PosZ) {
	RigidBody_Struct* newBody;
	if (m_Running == true) {
		// Add to collection
		AddToCollection(RigidBody,newBody)
		
		// Create the body.
		btRigidBody::btRigidBodyConstructionInfo cinfo(LinearMass,0,Shape->Shape,Shape->localInertia * AngularMass);
		POINT_TO_STATIC_MEMORY(btRigidBody,newBody->StaticBody,newBody->Body)
		newBody->Body = new(newBody->StaticBody) btRigidBody(cinfo);
		
		// Place the body
		btTransform NewTrans;
		NewTrans.setIdentity();
		NewTrans.setOrigin(btVector3(PosX,PosY,PosZ));
		newBody->Body->setWorldTransform(NewTrans);
		
		// Add it to the dynamics world
		m_PhysicsCore.dynamicsWorld->addRigidBody(newBody->Body);
		
		// Remember the linear and angular mass
		newBody->LinearMass = LinearMass;
		newBody->AngularMass = AngularMass;
		
		// Add 1 use of Shape
		newBody->Shape = Shape;
		Shape->useCount++;
		
		return newBody;
	} else {
		MQ->InsertMessage(L"You can't create a rigid body before starting the engine.");
		return 0;
	}
}
I did not show the rigid body destructor because the crash occur before it is even called.

The error remained when using btSimpleDynamicsWorld.
CookieMonster
Posts: 49
Joined: Sun Jan 29, 2012 10:01 pm

Re: Constraints and collisions cause instant crash.

Post by CookieMonster »

The physics works fine in module testing but not in my engine.

If I don't ignore libcmt.lib, I get the following errors:

Code: Select all

1>Linking...
1>libcmt.lib(pow.obj) : error LNK2005: _pow already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(sprintf.obj) : error LNK2005: _sprintf already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(vsnprnc.obj) : error LNK2005: _vsprintf_s already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(vswprnc.obj) : error LNK2005: _vswprintf_s already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(crt0dat.obj) : error LNK2005: __amsg_exit already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(crt0dat.obj) : error LNK2005: __initterm_e already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(fpinit.obj) : error LNK2005: __fltused already defined in a previous module
1>libcmt.lib(fpinit.obj) : error LNK2005: __ldused already defined in a previous module
1>libcmt.lib(tidtable.obj) : error LNK2005: __encode_pointer already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(tidtable.obj) : error LNK2005: __encoded_null already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(tidtable.obj) : error LNK2005: __decode_pointer already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(crt0init.obj) : error LNK2005: ___xi_a already defined in msvcrtd.lib(cinitexe.obj)
1>libcmt.lib(crt0init.obj) : error LNK2005: ___xi_z already defined in msvcrtd.lib(cinitexe.obj)
1>libcmt.lib(crt0init.obj) : error LNK2005: ___xc_a already defined in msvcrtd.lib(cinitexe.obj)
1>libcmt.lib(crt0init.obj) : error LNK2005: ___xc_z already defined in msvcrtd.lib(cinitexe.obj)
1>libcmt.lib(hooks.obj) : error LNK2005: "void __cdecl terminate(void)" (?terminate@@YAXXZ) already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(winxfltr.obj) : error LNK2005: ___CppXcptFilter already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(printf.obj) : error LNK2005: _printf already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(mlock.obj) : error LNK2005: __unlock already defined in msvcrtd.lib(MSVCR80D.dll)
1>libcmt.lib(mlock.obj) : error LNK2005: __lock already defined in msvcrtd.lib(MSVCR80D.dll)
mi076
Posts: 144
Joined: Fri Aug 01, 2008 6:36 am
Location: Bonn, Germany

Re: Constraints and collisions cause instant crash.

Post by mi076 »

there is a 50% chance that the step simulation call crash with access violation
not tested the code above, so not sure is the way trying to go good or not in general, but
in particular it might be memory alignment issue... the idea..

(from btSimpleBroadphase.cpp)

Code: Select all

void* mem = btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16);
m_pairCache = new (mem)btHashedOverlappingPairCache();
CookieMonster
Posts: 49
Joined: Sun Jan 29, 2012 10:01 pm

Re: Constraints and collisions cause instant crash.

Post by CookieMonster »

bt32BitAxisSweep3 crashed the same way.

I have improved the safety of my allocations but it did not help.

Code: Select all

// Placement new
// Make sure that the class being allocated is the same as new is calling the constructor for. Class inheritance does not work with this.
#include <new>
#define STORE_STATIC_MEMORY(CLASSNAME,POINTER) char POINTER##_Data##[sizeof(CLASSNAME)]; CLASSNAME##* POINTER;
#define CREATE_STATIC_OBJECT(CLASSNAME,POINTER,CONSTRUCTOR) POINTER = (CLASSNAME##*)(&##(POINTER##_Data)); POINTER = new(POINTER) CONSTRUCTOR ;
#define DESTROY_STATIC_OBJECT(CLASSNAME,POINTER) POINTER##->##~##CLASSNAME##();

/*
// Disable placement new
#define STORE_STATIC_MEMORY(CLASSNAME,POINTER) CLASSNAME##* POINTER;
#define CREATE_STATIC_OBJECT(CLASSNAME,POINTER,CONSTRUCTOR) POINTER = new CONSTRUCTOR ;
#define DESTROY_STATIC_OBJECT(CLASSNAME,POINTER) delete(POINTER);
*/
Using btAlignedAllocSetCustom to replace the allocator with a placeholder did not work.
mi076
Posts: 144
Joined: Fri Aug 01, 2008 6:36 am
Location: Bonn, Germany

Re: Constraints and collisions cause instant crash.

Post by mi076 »

I have improved the safety of my allocations but it did not help.
as far i can see you still allocate sizeof(CLASSNAME) memory for things like

Code: Select all

Core->dispatcher = new(Core->dispatcher) btCollisionDispatcher(Core->collisionConfiguration);
... it is wrong. Use aligned allocator. There is one in Bullet and Visual Studio 2010 has also _aligned_malloc(size, alignment) build in.

Code: Select all

void* mem = btAlignedAlloc(sizeof(CLASSNAME),16);
or

Code: Select all

void* mem = _aligned_malloc(sizeof(CLASSNAME),16);
If you simple use "new btSomething(...)" you probably use aligned allocator... There is a macro BT_DECLARE_ALIGNED_ALLOCATOR() in Bullet which replaces default "new" operator with aligned allocator...
CookieMonster
Posts: 49
Joined: Sun Jan 29, 2012 10:01 pm

Re: Constraints and collisions cause instant crash.

Post by CookieMonster »

By using the lower macro definitions in the comment, placement is replaced by regular allocations like in the examples but that also crash.
That means that there are more than just one bug.

I might have found the second error. m_PhysicsCore.dynamicsWorld was null when removing the first rigid body.
It was a macro error because all variables in the core are declared in a table so that the engine is released automatically before the objects.

It is running without a problem now, thanks! :)