UB with operator=() for Ogre::Pass

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
Post Reply
crousser
Gnoblar
Posts: 12
Joined: Tue Dec 18, 2007 2:05 pm

UB with operator=() for Ogre::Pass

Post by crousser »

Hello everyone
I apologize for my bad english =).

Earlier, I drew attention to the UB's with multi-scene manageres.
But now, I have used only one scene and periodically my app crashes. I understand what is the actual cause of crash, I think..

Look at Ogree::OgrePass.cpp

Code: Select all

    Pass& Pass::operator=(const Pass& oth)
    {
       mName = oth.mName;
       mHash = oth.mHash;              // <---------- it's very interesting (that hide UB)
       mAmbient = oth.mAmbient;
//
//  bla-bla-bal
//

       _dirtyHash();                       // <----------- it's very interesting to, but does not matter =) (hash was changed earlier and see below)

       return *this;
    }
If you remember - these objects can be stored as a key in std :: map .. (Pass::msDirtyHashList, and QueuedRenderableCollection::mGrouped)
Suppose in the previous frame, an object was placed in one of QueuedRenderableCollection :: mGruped and has not been marked as dirty (give it a some name - pass1)
Next frame starts executing my listner frameStarted which comprises the following code

Code: Select all


//  bla-bla-bal
auto pass2 = someMaterial->getBestTechnique(0)->getPass(0) ;

*pass1 = *pass2;

// bla-bla-bal
Thereafter, pass1 has invalid hash (if hash was changed other value), marked as dirty.. but - it references in QueuedRenderableCollection::mGrouped translates into inconsistent state all map

I walked around this problem with the following code:

Code: Select all

void _forceClearWorkGroupFromDirtyPasses()
{
	Ogre::Root* m_Root = Ogre::Root::getSingletonPtr();
	if (m_Root && (!Ogre::Pass::getDirtyHashList().empty() || !Ogre::Pass::getPassGraveyard().empty()))
	{
		Ogre::SceneManagerEnumerator::SceneManagerIterator scenesIter = m_Root->getSceneManagerIterator();

		while (scenesIter.hasMoreElements())
		{
			Ogre::SceneManager* pScene = scenesIter.getNext();
			if (pScene)
			{
				Ogre::RenderQueue* pQueue = pScene->getRenderQueue();
				if (pQueue)
				{
					Ogre::RenderQueue::QueueGroupIterator groupIter = pQueue->_getQueueGroupIterator();
					while (groupIter.hasMoreElements())
					{
						Ogre::RenderQueueGroup* pGroup = groupIter.getNext();
						if (pGroup)
							pGroup->clear(false);
					}
				}
			}
		}
	}
}

void assignmentOgrePasses(Ogre::Pass * _lPass, Ogre::Pass * _rPass)
{
	assert(_lPass && _rPass);

	// prepare passes for re-calculate hash
	_lPass->_dirtyHash();
	_rPass->_dirtyHash();
	_forceClearWorkGroupFromDirtyPasses();

	// assign
	*_lPass = *_rPass;

        // call recalculate dirty hashes
	Ogre::Pass::processPendingPassUpdates();
}

//
//  bla-bla-bal ....
//
auto pass2 = someMaterial->getBestTechnique(0)->getPass(0) ;

assignmentOgrePasses(pass1 , pass2)

// bla-bla-bal

I see before that and that , but realized that there is no one answer here
Post Reply