Visual debugger step crash

Visual debugger step crash

Hi!

I've followed all the tutorials and docs and even copy pasted the code, but my project keeps crashing if i step the visual debugger instance, when the visual debugger itself is launched.

In details.

Here is my initialization code:

	hkMallocAllocator baseMalloc;
  hkMemoryRouter *memoryRouter = hkMemoryInitUtil::initDefault(&baseMalloc, hkMemorySystem::FrameInfo(1024 * 1024 * 1024));
  hkBaseSystem::init(memoryRouter, ErrorReport);

  hkpWorldCinfo worldInfo;
  currentWorld = new hkpWorld(worldInfo);

  hkpAgentRegisterUtil::registerAllAgents(currentWorld->getCollisionDispatcher());
  hkpPhysicsContext::registerAllPhysicsProcesses();

  currentContext = new hkpPhysicsContext;
  currentContext->addWorld(currentWorld);

  hkArray contexts;
  contexts.pushBack(currentContext);

  currentVisualDebugger = new hkVisualDebugger(contexts);
  currentVisualDebugger->serve();

As you can see, nothing really special here.

And here is how i step the world every frame:

  currentWorld->stepDeltaTime(0.01f);
  currentVisualDebugger->step();

This works perfectly, until i connect with a visual debugger to my app. The VDB itself registers the connection in it's local console output and then my app crashes with a:

0xC0000005: Access violation reading location 0xccccccd8.

And the call stack:

GHostEngine.dll!hkLargeBlockAllocator::blockAlloc(int bytes) Line 736 + 0x13 bytes C++
GHostEngine.dll!hkFreeListAllocator::bufAlloc(int & reqNumInOut) Line 553 + 0xc bytes C++
GHostEngine.dll!hkFreeListAllocator::blockAlloc(int nbytes) Line 575 C++
GHostEngine.dll!hkMemoryRouter::alignedAlloc(hkMemoryAllocator & b, int nbytes, int alignment) Line 43 + 0x29 bytes C++
GHostEngine.dll!hkBufferedStreamWriter::hkBufferedStreamWriter(hkStreamWriter * s, int bufSize) Line 40 C++
GHostEngine.dll!hkDisplaySerializeOStream::hkDisplaySerializeOStream(hkStreamWriter * writer) Line 39 + 0x5a bytes C++
GHostEngine.dll!hkVersionReporter::sendVersionInformation(hkStreamWriter * connection) Line 147 C++
GHostEngine.dll!hkVisualDebugger::createClient(hkSocket * socket, hkStreamReader * reader, hkStreamWriter * writer) Line 237 + 0x6 bytes C++
GHostEngine.dll!hkVisualDebugger::pollForNewClients() Line 287 C++
GHostEngine.dll!hkVisualDebugger::step(float frameTimeInMs) Line 323 C++

The error reporter on init says:

Havok Message .\\hkVisualDebugger.cpp(44): [0x1293ADEF] Report : VDB Server instance has been created
Havok Message .\\System\\Io\\Socket\\Bsd\\hkBsdSocket.cpp(396): [0x1293ADE8] Report : Listening on host[-] port 25001
Havok Message .\\hkVisualDebugger.cpp(107): [0x1293ADE8] Report : Server created and will poll for new client(s) on port 25001 every frame

And after connection:

Havok Message .\\System\\Io\\Socket\\Bsd\\hkBsdSocket.cpp(451): [0xFFFFFFFF] Report : Socket got connection from [127.0.0.1:49883]
Havok Message .\\hkVisualDebugger.cpp(280): [0xFFFFFFFF] Report : A new network client has been received (host name not available at present)

I just don't understand what i did wrong. All the demos work OK with VDB, but not my app.

P.S.

There are no bodies added to the world. Basically, these are the only Havok functions i used. Nothing else (except for deinitialization).

10 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Anyone? Maybe i have to setup or define or include something?

And only the echo whispers "Diiig the cooode.... diig the coode.... dig...."

Anyway... looks like there should be some mentioning (or there is?) in the docs or samples, that "hkMallocAllocator baseMalloc" which is used to init memory managment, should be at global scope. Or use "hkMallocAllocator::m_defaultMallocAllocator". It's just that my first thought about it was that it's a descriptor of some sort and data is copied from it. But looks like it's not.

The standalone step-by-step demos all use local variable, but since they are just a small piece of one CPP file with all the code contained in one MAIN function, that is not a problem.

In other words, if anyone gets the same problems (but i guess i'm the first one), the solution is simple.

Thanks so -f'ing much! This was EXACTLY the problem my team and I were having!

You literally saved the day...

I am having the exact same issue even when using the hkMallocAllocator::m_defaultMallocAllocator.

Havok is running in a multithreading environment and I wonder if it's not he issue.
Initialisation is the same as in the Standalone demo from Havok package.

Kissy

Hey Kissy,

You're not callinghkMemoryInitUtil::initDefault from multiple threads are you? The base init needs to be done only once, from the master thread. Other threads need todo the steps discussed in the docs under "Common Havok Components > Base Library > The Base System > Runtime Initialization > Per-Thread Initialization" - and make sure they are not initialized before the master thread inits the BaseSystem and MemorySystem.

Hmm, you should also make sure that you're callinghkMemoryInitUtil::initDefaultafter/within main() (ie. not from a global variable's constructor). Otherwise you may run in to the infamous "initialization of globals is undefined between translation units" C++ gotcha. In this casehkMallocAllocator::m_defaultMallocAllocator might be uninitialized when you are trying to initialize the memory system.

You also want to make sure you build in debug so that you get all the warnings and asserts.
If you're still hitting this issue could you post any console errors and your initialization code?

-Tyler

Hey Tyler,

Thanks for your help, However I cannot see what I did wrong in my code :)
I am calling hkMemoryInitUtil::initDefault from the MainThread, then calling hkBaseSystem::initThread() from all worker threads.

Here is my code initialisation :

void methodCalledByMainThread() {
	//
	// Initialize Havok.
	//
	hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initDefault( hkMallocAllocator::m_defaultMallocAllocator, hkMemorySystem::FrameInfo( 500* 1024 ) );
	hkBaseSystem::init( memoryRouter, ErrorReport, this );

	//
	// Allocate memory for each thread via a callback.
	//
	s_idMainThread = ::GetCurrentThreadId();

	//
	// This is a blocking function that wait that all thread are done
	//
	g_Managers.pTask->NonStandardPerThreadCallback(
		reinterpret_cast(AllocateThreadResources), this
		);

	//
	// Create the jobQueue
	// TODO : move this to Framework maybe ?
	//
	hkJobQueueCinfo info;
	info.m_jobQueueHwSetup.m_numCpuThreads = 4;
	m_jobQueue = new hkJobQueue(info);
	
	m_pScene = new HavokScene( this );
	// Initialize function of HavokScene class is called later by the MainThread
        // The code for HavokScene::Initialize is under
}

void
HavokPhysicsSystem::AllocateThreadResources(
	HavokPhysicsSystem* pSystem
	)
{
	//
	// Do not initialize main thread. 
	// Already done in mainInit
	//
	u32 currentThreadId = ::GetCurrentThreadId();
	if ( currentThreadId == s_idMainThread )
		return;

	//
	// Create thread memory for the thread.
	//
	hkMemoryRouter memoryRouter;
	hkMemorySystem::getInstance().threadInit( memoryRouter, "PhysicSystemWorker" );
	hkResult result = hkBaseSystem::initThread( &memoryRouter );

	ASSERT ( result == HK_SUCCESS );
	
	//
	// Storing memoryRouter to call quitThread on quit
	// (Don't know if it's really needed)
	//
	WorkerMemoryRouterPair_t newPair;
	newPair.first = ::GetCurrentThreadId();
	newPair.second = &memoryRouter;
	s_workerMemoryRouterMap.insert( newPair );
}

HavokPhysicsScene :

void
HavokPhysicsScene::Initialize(
	void
	)
{

	//
	// Create the world with default values.
	//
	hkpWorldCinfo WorldCInfo;
	WorldCInfo.m_simulationType = hkpWorldCinfo::SIMULATION_TYPE_MULTITHREADED;
	WorldCInfo.m_broadPhaseBorderBehaviour = hkpWorldCinfo::BROADPHASE_BORDER_REMOVE_ENTITY;
	WorldCInfo.m_gravity.set( 0, -9.8f, 0 );

	m_pWorld = new hkpWorld( WorldCInfo );
	ASSERT( m_pWorld != NULL );

	m_pWorld->markForWrite();

	hkpAgentRegisterUtil::registerAllAgents( m_pWorld->getCollisionDispatcher() );

	//
	// Register the jobQueue to use
	//
	m_pWorld->registerWithJobQueue( static_cast( m_pSystem )->getJobQueue() );
	
	//
	//  Create the ground box
	//
	{
		hkVector4 groundRadii( 70.0f, 2.0f, 140.0f );
		hkpConvexShape* shape = new hkpBoxShape( groundRadii , 0 );

		hkpRigidBodyCinfo ci;

		ci.m_shape = shape;
		ci.m_motionType = hkpMotion::MOTION_FIXED;
		ci.m_position = hkVector4( 0.0f, -2.0f, 0.0f );
		ci.m_qualityType = HK_COLLIDABLE_QUALITY_FIXED;

		m_pWorld->addEntity( new hkpRigidBody( ci ) )->removeReference();
		shape->removeReference();
	}

	//
	// Create the task for simulating physics.
        // Constructor for HavokPhysicsTask is under
	//
	m_pTask = new HavokPhysicsTask( this, m_pWorld );
	ASSERT( m_pTask != NULL );

	m_pWorld->unmarkForWrite();
}

HavokPhysicsTask :

// Also called by the MainThread so
HavokPhysicsTask::HavokPhysicsTask(
	HavokPhysicsScene* pScene,
	hkpWorld* pWorld
	)
	: ISystemTask( pScene )
	, m_pScene( pScene )
	, m_pWorld( pWorld )
{
	ASSERT( m_pScene != NULL );
	ASSERT( m_pWorld != NULL );

	m_pWorld->addEntityListener( this );

#ifdef __HAVOK_VDB__ => This is enabled
	m_pWorld->markForWrite();

	//
	// Create the physics context for the visual debugger.
	//
	m_pPhysicsContext = new hkpPhysicsContext;
	m_pPhysicsContext->addWorld( m_pWorld );
	ASSERT( m_pPhysicsContext != NULL );

	hkpPhysicsContext::registerAllPhysicsProcesses();

	//
	// Create the visual debugger.
	//
	hkArray Contexts;
	Contexts.pushBack( m_pPhysicsContext );

	m_pVisualDebugger = new hkVisualDebugger( Contexts );
	ASSERT( m_pVisualDebugger != NULL );

	m_pVisualDebugger->serve();
	m_pVisualDebugger->addDefaultProcess( "Shapes" );
	m_pVisualDebugger->addDefaultProcess( "Broadphase" );
	m_pVisualDebugger->addDefaultProcess( "Islands" );
	m_pVisualDebugger->addDefaultProcess( "CentreOfMass" );
	m_pVisualDebugger->addDefaultProcess( "Phantom" );

	m_pWorld->unmarkForWrite();
#endif
}

This part is called by one of the worker thread (not the main thread)
after the finishMtStep call. Maybe this is the issue ? step is not called by the same thread
that did the initDefault ?

// Then, in the worker threads, just after finishMtStep
#ifdef __HAVOK_VDB__
        m_pWorld->finishMtStep();
        m_pWorld->lock();
	if ( m_pVisualDebugger != NULL )
	{
		//m_pPhysicsContext->syncTimers();
		m_pVisualDebugger->step();
	}
        m_pWorld->unlock();
#endif

I use the debug multithread static libs and run with HK_DEBUG preprocessor directive. Is that correct ?

As far as I know, I don't get any other Assert or Error except when I try to connect the VisualDebugger
I get the "Report : Socket got connection from [127.0.0.1:XXXX]"

Thanks
Kissy

Hello,

my issue seems to come from the hkBsdSocket::pollForNewClient() method.
I got a "Read violation exception" inside this method while calling the setsockopt api.

Does anyone already got this issue ?

 	ntdll.dll!774915de() 	
 	ntdll.dll!774915de() 	
 	ntdll.dll!7748014e() 	
 	mswsock.dll!73b93f15() 	
 	mswsock.dll!73b93f24() 	
 	ws2_32.dll!752a2f7d() 	
 	ws2_32.dll!752a423f() 	
 	ws2_32.dll!752a423f() 	
 	wsock32.dll!73bd1935() 	
	PhysicSystem.dll!hkBsdSocket::pollForNewClient()  Ligne 463	C++
 	PhysicSystem.dll!hkVisualDebugger::pollForNewClients()  Ligne 294 + 0xa octets	C++
 	PhysicSystem.dll!hkVisualDebugger::step(float frameTimeInMs)  Ligne 340	C++

Regards

Hi Kissy,

This part is called by one of the worker thread (not the main thread)
after thefinishMtStepcall. Maybe this is the issue ? step is not called by the same thread that did theinitDefault?

- This is what I suspect. Have you tried calling the physics step and vdb from the main thread? To debug you could try using the single threaded physics step function.

I use the debug multithread static libs and run with HK_DEBUG preprocessor directive.

- This is correct. If you have multiple projects or libs that you are building for your game make sure that they are all linking against the same Havok libs (eg. all debug multithreaded libs).

Otherwise nothing sticks out at me and your setup code looks correct.
-Tyler

Hello Tyler,

Actually you are right, for references :
initMtStep, finishMtStep, and vdb->serve() must be called by the same thread
when using Havok in a multithreaded environment :)

Thanks a lot,
Kissy

Login to leave a comment.