<div dir="ltr"><div dir="ltr">Hi Fabian,<br></div> <div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">My build is using static osg, static osg-plugins and link time optimization.<div>I created an address sanitizer enabled build.</div><div>It exhibits a heap-use-after-free.<br></div>I will try to further investigate this week.<br><div><br></div><div>=================================================================<br>==11872==ERROR: AddressSanitizer: heap-use-after-free on address 0x6030000082c0 at pc 0x55b4b9659551 bp 0x7ffdf8a9c190 sp 0x7ffdf8a9c180<br>READ of size 8 at 0x6030000082c0 thread T0<br>    #0 0x55b4b9659550 in OpenThreads::ScopedPointerLock<OpenThreads::Mutex>::ScopedPointerLock(OpenThreads::Mutex*) ./openmw/extern-git/OpenSceneGraph/include/OpenThreads/ScopedLock:54<br>    #1 0x55b4b9659550 in osg::StateAttribute::removeParent(osg::StateSet*) ./openmw/extern-git/OpenSceneGraph/src/osg/StateAttribute.cpp:38<br>    #2 0x55b4b965a033 in osg::StateSet::clear() ./openmw/extern-git/OpenSceneGraph/src/osg/StateSet.cpp:734<br></div></div></blockquote><div><br></div><div>Given the stack trace it kinda looks like the getRefMutex() call in StateAttribute.cpp is the where things might be going astray (note the comment I've added below):</div><div><br></div><div>void StateAttribute::removeParent(osg::StateSet* object)<br>{<br>    OpenThreads::ScopedPointerLock<OpenThreads::Mutex> lock(getRefMutex()); // calls the base classes Referenced::getRefMutex() method that will map to Referenced::getGlobalReferencedMutex<br><br>    ParentList::iterator pitr = std::find(_parents.begin(),_parents.end(),object);<br>    if (pitr!=_parents.end()) _parents.erase(pitr);<br>}</div><div><br></div><div>The Referenced::getGlobalReferencedMutex() implementation in Referenced.cpp is:</div><div><br></div><div>OpenThreads::Mutex* Referenced::getGlobalReferencedMutex()<br>{<br>    static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex;<br>    return s_ReferencedGlobalMutext.get();<br>}<br><br>// helper class for forcing the global mutex to be constructed when the library is loaded.<br>struct InitGlobalMutexes<br>{<br>    InitGlobalMutexes()<br>    {<br>        Referenced::getGlobalReferencedMutex();<br>    }<br>};<br>static InitGlobalMutexes s_initGlobalMutexes;</div><div><br></div><div>Which is all a bit hacky way of trying to get a singleton's _ReferencedGlobalMutext to construct before any other code calling getGlobalReferencedMutex() gets called.</div><div><br></div><div>I don't really know why a pointer is even being used here, it's not how I'd write the code these days, but off the top of my head don't recall the derivation and motivations between all this code as it dates back to the earliest days of the OSG project, so almost two decades :-)</div><div><br></div><div>What I'd write today would simply be:<br></div><div><br></div><div>static OpenThreads::Mutex s_ReferencedGlobalMutex;<br>OpenThreads::Mutex* Referenced::getGlobalReferencedMutex()<br>{<br>    return &s_ReferencedGlobalMutex;<br>}</div><div><br></div><div>You could try substituting this in.  I will try a build here just to make sure the above works fine for standard OSG work.  I don't expect this change to have any affect on your own code, if it does it suggest there is some issue with order of clean up of statics.<br></div><div><br></div><div>Robert.<br></div></div></div>