Physics Simulation Forum

 

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Thu Mar 15, 2012 12:10 pm 
Offline

Joined: Sun Jan 29, 2012 10:01 pm
Posts: 49
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:
#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.


Top
 Profile  
 
PostPosted: Fri Mar 16, 2012 10:55 pm 
Offline

Joined: Sun Jan 29, 2012 10:01 pm
Posts: 49
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:
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)


Top
 Profile  
 
PostPosted: Sat Mar 17, 2012 12:28 am 
Offline

Joined: Fri Aug 01, 2008 6:36 am
Posts: 144
Location: Bonn, Germany
Quote:
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:
void* mem = btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16);
m_pairCache = new (mem)btHashedOverlappingPairCache();


Top
 Profile  
 
PostPosted: Sat Mar 17, 2012 11:03 am 
Offline

Joined: Sun Jan 29, 2012 10:01 pm
Posts: 49
bt32BitAxisSweep3 crashed the same way.

I have improved the safety of my allocations but it did not help.
Code:
// 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.


Top
 Profile  
 
PostPosted: Sat Mar 17, 2012 5:50 pm 
Offline

Joined: Fri Aug 01, 2008 6:36 am
Posts: 144
Location: Bonn, Germany
Quote:
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:
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:
void* mem = btAlignedAlloc(sizeof(CLASSNAME),16);

or
Code:
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...


Top
 Profile  
 
PostPosted: Sun Mar 18, 2012 10:12 am 
Offline

Joined: Sun Jan 29, 2012 10:01 pm
Posts: 49
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! :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group