Skip to content
GitLab
    • GitLab: the DevOps platform
    • Explore GitLab
    • Install GitLab
    • How GitLab compares
    • Get started
    • GitLab docs
    • GitLab Learn
  • Pricing
  • Talk to an expert
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
    • Switch to GitLab Next
    Projects Groups Topics Snippets
  • Register
  • Sign in
  • openmw openmw
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
    • Locked files
  • Issues 831
    • Issues 831
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 32
    • Merge requests 32
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • OpenMWOpenMW
  • openmwopenmw
  • Issues
  • #4764
Closed
Open
Issue created Dec 24, 2018 by thexyz@thexyz

Data race in osg ParticleSystem (triggered when jumping into water)

Log:

WARNING: ThreadSanitizer: data race (pid=7927)
  Write of size 8 at 0x7b6000020160 by main thread:
    #0 void std::vector<osgParticle::Particle, std::allocator<osgParticle::Particle> >::_M_realloc_insert<osgParticle::Particle const&>(__gnu_cxx::__normal_iterator<osgParticle::Particle*, std::vector<osgParticle::Particle, std::allocator<osgParticle::Particle> > >, osgParticle::Particle const&) /usr/lib/gcc/x86_64-pc-linux-gnu/7.3.0/include/g++-v7/bits/vector.tcc:452 (libosgParticle.so.160+0x0000000be0b0)
    #1 std::vector<osgParticle::Particle, std::allocator<osgParticle::Particle> >::push_back(osgParticle::Particle const&) /usr/lib/gcc/x86_64-pc-linux-gnu/7.3.0/include/g++-v7/bits/stl_vector.h:948 (libosgParticle.so.160+0x0000000bb7ad)
    #2 osgParticle::ParticleSystem::createParticle(osgParticle::Particle const*) /home/xyz/osg/src/osgParticle/ParticleSystem.cpp:128 (libosgParticle.so.160+0x0000000b2b43)
    #3 MWRender::RippleSimulation::emitRipple(osg::Vec3f const&) /home/xyz/openmw/apps/openmw/mwrender/ripplesimulation.cpp:199 (openmw+0x000000e7c2a5)
    #4 MWRender::RippleSimulation::update(float) /home/xyz/openmw/apps/openmw/mwrender/ripplesimulation.cpp:142 (openmw+0x000000e7bc9b)
    #5 MWRender::Water::update(float) /home/xyz/openmw/apps/openmw/mwrender/water.cpp:657 (openmw+0x000000e6bded)
    #6 MWRender::RenderingManager::update(float, bool) /home/xyz/openmw/apps/openmw/mwrender/renderingmanager.cpp:599 (openmw+0x000000d77fb6)
    #7 MWWorld::Scene::update(float, bool) /home/xyz/openmw/apps/openmw/mwworld/scene.cpp:327 (openmw+0x00000127c6ef)
    #8 MWWorld::World::update(float, bool) /home/xyz/openmw/apps/openmw/mwworld/worldimp.cpp:1795 (openmw+0x00000121f609)
    #9 OMW::Engine::frame(float) /home/xyz/openmw/apps/openmw/engine.cpp:162 (openmw+0x0000016699f4)
    #10 OMW::Engine::go() /home/xyz/openmw/apps/openmw/engine.cpp:716 (openmw+0x000001670078)
    #11 runApplication(int, char**) /home/xyz/openmw/apps/openmw/main.cpp:252 (openmw+0x00000164e5a2)
    #12 wrapApplication(int (*)(int, char**), int, char**, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/xyz/openmw/components/debug/debugging.cpp:135 (openmw+0x00000186e9b3)
    #13 main /home/xyz/openmw/apps/openmw/main.cpp:264 (openmw+0x00000164e69b)

  Previous read of size 8 at 0x7b6000020160 by thread T1 (mutexes: write M43482437885932392):
    #0 std::vector<osgParticle::Particle, std::allocator<osgParticle::Particle> >::size() const /usr/lib/gcc/x86_64-pc-linux-gnu/7.3.0/include/g++-v7/bits/stl_vector.h:671 (openmw+0x000000de5b28)
    #1 osgParticle::ParticleSystem::drawImplementation(osg::RenderInfo&) const /home/xyz/osg/src/osgParticle/ParticleSystem.cpp:222 (libosgParticle.so.160+0x0000000b3358)
    #2 osg::Drawable::drawInner(osg::RenderInfo&) const /home/xyz/osg/include/osg/Drawable:276 (libosg.so.160+0x0000004842be)
    #3 osg::Drawable::draw(osg::RenderInfo&) const /home/xyz/osg/src/osg/Drawable.cpp:688 (libosg.so.160+0x000000483449)
    #4 osgUtil::RenderLeaf::render(osg::RenderInfo&, osgUtil::RenderLeaf*) /home/xyz/osg/src/osgUtil/RenderLeaf.cpp:64 (libosgUtil.so.160+0x000000586460)
    #5 osgUtil::RenderBin::drawImplementation(osg::RenderInfo&, osgUtil::RenderLeaf*&) /home/xyz/osg/src/osgUtil/RenderBin.cpp:467 (libosgUtil.so.160+0x000000572c0c)
    #6 osgUtil::RenderBin::draw(osg::RenderInfo&, osgUtil::RenderLeaf*&) /home/xyz/osg/src/osgUtil/RenderBin.cpp:430 (libosgUtil.so.160+0x00000057295b)
    #7 osgUtil::RenderBin::drawImplementation(osg::RenderInfo&, osgUtil::RenderLeaf*&) /home/xyz/osg/src/osgUtil/RenderBin.cpp:517 (libosgUtil.so.160+0x000000572f7a)
    #8 osgUtil::RenderStage::drawImplementation(osg::RenderInfo&, osgUtil::RenderLeaf*&) /home/xyz/osg/src/osgUtil/RenderStage.cpp:1406 (libosgUtil.so.160+0x00000058e349)
    #9 osgUtil::RenderBin::draw(osg::RenderInfo&, osgUtil::RenderLeaf*&) /home/xyz/osg/src/osgUtil/RenderBin.cpp:430 (libosgUtil.so.160+0x00000057295b)
    #10 osgUtil::RenderStage::drawInner(osg::RenderInfo&, osgUtil::RenderLeaf*&, bool&) /home/xyz/osg/src/osgUtil/RenderStage.cpp:931 (libosgUtil.so.160+0x00000058c309)
    #11 osgUtil::RenderStage::draw(osg::RenderInfo&, osgUtil::RenderLeaf*&) /home/xyz/osg/src/osgUtil/RenderStage.cpp:1242 (libosgUtil.so.160+0x00000058d967)
    #12 osgUtil::SceneView::draw() /home/xyz/osg/src/osgUtil/SceneView.cpp:1367 (libosgUtil.so.160+0x0000005a71b4)
    #13 osgViewer::Renderer::draw() /home/xyz/osg/src/osgViewer/Renderer.cpp:774 (libosgViewer.so.160+0x00000019c018)
    #14 osgViewer::Renderer::operator()(osg::GraphicsContext*) /home/xyz/osg/src/osgViewer/Renderer.cpp:929 (libosgViewer.so.160+0x00000019d458)
    #15 osg::GraphicsContext::runOperations() /home/xyz/osg/src/osg/GraphicsContext.cpp:696 (libosg.so.160+0x0000004f76b1)
    #16 osg::RunOperations::operator()(osg::GraphicsContext*) /home/xyz/osg/src/osg/GraphicsThread.cpp:139 (libosg.so.160+0x0000005073ae)
    #17 osg::GraphicsOperation::operator()(osg::Object*) /home/xyz/osg/src/osg/GraphicsThread.cpp:53 (libosg.so.160+0x0000005068c6)
    #18 osg::OperationThread::run() /home/xyz/osg/src/osg/OperationThread.cpp:438 (libosg.so.160+0x0000005b4b05)
    #19 osg::GraphicsThread::run() /home/xyz/osg/src/osg/GraphicsThread.cpp:38 (libosg.so.160+0x0000005067ea)
    #20 OpenThreads::ThreadPrivateActions::StartThread(void*) <null> (libOpenThreads.so.21+0x00000000a2ba)
    #21 <null> <null> (libtsan.so.0+0x00000002583b)

  Location is heap block of size 920 at 0x7b6000020000 allocated by main thread:
    #0 operator new(unsigned long) <null> (libtsan.so.0+0x00000006f546)
    #1 MWRender::RippleSimulation::RippleSimulation(osg::Group*, Resource::ResourceSystem*, Fallback::Map const*) /home/xyz/openmw/apps/openmw/mwrender/ripplesimulation.cpp:87 (openmw+0x000000e7b1fa)
    #2 MWRender::Water::Water(osg::Group*, osg::Group*, Resource::ResourceSystem*, osgUtil::IncrementalCompileOperation*, Fallback::Map const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/xyz/openmw/apps/openmw/mwrender/water.cpp:404 (openmw+0x000000e69349)
    #3 MWRender::RenderingManager::RenderingManager(osgViewer::Viewer*, osg::ref_ptr<osg::Group>, Resource::ResourceSystem*, SceneUtil::WorkQueue*, Fallback::Map const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DetourNavigator::Navigator&) /home/xyz/openmw/apps/openmw/mwrender/renderingmanager.cpp:254 (openmw+0x000000d73a8c)
    #4 MWWorld::World::World(osgViewer::Viewer*, osg::ref_ptr<osg::Group>, Resource::ResourceSystem*, SceneUtil::WorkQueue*, Files::Collections const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, ToUTF8::Utf8Encoder*, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/xyz/openmw/apps/openmw/mwworld/worldimp.cpp:236 (openmw+0x000001210bf5)
    #5 OMW::Engine::prepareEngine(Settings::Manager&) /home/xyz/openmw/apps/openmw/engine.cpp:535 (openmw+0x00000166e3a1)
    #6 OMW::Engine::go() /home/xyz/openmw/apps/openmw/engine.cpp:663 (openmw+0x00000166f5dc)
    #7 runApplication(int, char**) /home/xyz/openmw/apps/openmw/main.cpp:252 (openmw+0x00000164e5a2)
    #8 wrapApplication(int (*)(int, char**), int, char**, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/xyz/openmw/components/debug/debugging.cpp:135 (openmw+0x00000186e9b3)
    #9 main /home/xyz/openmw/apps/openmw/main.cpp:264 (openmw+0x00000164e69b)

  Mutex M43482437885932392 is already destroyed.

  Thread T1 (tid=8022, running) created by main thread at:
    #0 pthread_create <null> (libtsan.so.0+0x000000028e53)
    #1 OpenThreads::Thread::start() /home/xyz/osg/src/OpenThreads/pthreads/PThread.cpp:671 (libOpenThreads.so.21+0x000000008e1c)
    #2 OpenThreads::Thread::startThread() /home/xyz/osg/src/OpenThreads/pthreads/PThread.cpp:694 (libOpenThreads.so.21+0x000000008ec9)
    #3 osgViewer::ViewerBase::startThreading() /home/xyz/osg/src/osgViewer/ViewerBase.cpp:600 (libosgViewer.so.160+0x000000208354)
    #4 osgViewer::ViewerBase::setUpThreading() /home/xyz/osg/src/osgViewer/ViewerBase.cpp:302 (libosgViewer.so.160+0x000000206bab)
    #5 osgViewer::Viewer::realize() /home/xyz/osg/src/osgViewer/Viewer.cpp:612 (libosgViewer.so.160+0x0000001fc57b)
    #6 OMW::Engine::createWindow(Settings::Manager&) /home/xyz/openmw/apps/openmw/engine.cpp:414 (openmw+0x00000166c59f)
    #7 OMW::Engine::prepareEngine(Settings::Manager&) /home/xyz/openmw/apps/openmw/engine.cpp:448 (openmw+0x00000166d129)
    #8 OMW::Engine::go() /home/xyz/openmw/apps/openmw/engine.cpp:663 (openmw+0x00000166f5dc)
    #9 runApplication(int, char**) /home/xyz/openmw/apps/openmw/main.cpp:252 (openmw+0x00000164e5a2)
    #10 wrapApplication(int (*)(int, char**), int, char**, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/xyz/openmw/components/debug/debugging.cpp:135 (openmw+0x00000186e9b3)
    #11 main /home/xyz/openmw/apps/openmw/main.cpp:264 (openmw+0x00000164e69b)

SUMMARY: ThreadSanitizer: data race /usr/lib/gcc/x86_64-pc-linux-gnu/7.3.0/include/g++-v7/bits/vector.tcc:452 in void std::vector<osgParticle::Particle, std::allocator<osgParticle::Particle> >::_M_realloc_insert<osgParticle::Particle const&>(__gnu_cxx::__normal_iterator<osgParticle::Particle*, std::vector<osgParticle::Particle, std::allocator<osgParticle::Particle> > >, osgParticle::Particle const&)

This looks like a bug in OSG to me, but maybe it's just OpenMW doing something with OSG it shouldn't? I couldn't find any thread safety guarantees in OSG docs.

So what's happening is OpenMW is inserting a particle using createParticle and the function is writing to the _particles vector here: https://github.com/OpenMW/osg/blob/ecedf3232c2f1b3b6a2f06f77ea37a9afb6a93f5/src/osgParticle/ParticleSystem.cpp#L119

Meanwhile, the render thread is accessing the same _particles in drawImplementation here https://github.com/OpenMW/osg/blob/ecedf3232c2f1b3b6a2f06f77ea37a9afb6a93f5/src/osgParticle/ParticleSystem.cpp#L222

There's an "rw" lock but it's only used in drawImplementation and not in createParticle.

Adding a ScopedWriteLock lock(_readWriteMutex); as the first line in osgParticle::ParticleSystem::createParticle should resolve the race but again I'm not sure if the problem's OpenMW using OSG wrong or it's a legitimate bug in OSG.

Assignee
Assign to
Time tracking