Data race in ChunkManager -> Array::setBinding
Log:
WARNING: ThreadSanitizer: data race (pid=7927)
Write of size 4 at 0x7b2800145250 by thread T2:
#0 osg::Array::setBinding(osg::Array::Binding) /home/xyz/osg/include/osg/Array:189 (libosg.so.160+0x0000004b1174)
#1 osg::Geometry::setTexCoordArray(unsigned int, osg::Array*, osg::Array::Binding) /home/xyz/osg/src/osg/Geometry.cpp:247 (libosg.so.160+0x0000004a7504)
#2 osg::Geometry::setTexCoordArray(unsigned int, osg::Array*) /home/xyz/openmw-prefix/include/osg/Geometry:79 (openmw+0x0000016ec485)
#3 Terrain::ChunkManager::createChunk(float, osg::Vec2f const&, int, unsigned int) /home/xyz/openmw/components/terrain/chunkmanager.cpp:206 (openmw+0x0000018eeef6)
#4 Terrain::ChunkManager::getChunk(float, osg::Vec2f const&, int, unsigned int) /home/xyz/openmw/components/terrain/chunkmanager.cpp:47 (openmw+0x0000018ed28f)
#5 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:58 (openmw+0x0000018ea0f3)
#6 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:53 (openmw+0x0000018ea07e)
#7 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:50 (openmw+0x0000018e9e90)
#8 Terrain::TerrainGrid::cacheCell(Terrain::View*, int, int) /home/xyz/openmw/components/terrain/terraingrid.cpp:37 (openmw+0x0000018e9cb5)
#9 MWWorld::PreloadItem::doWork() /home/xyz/openmw/apps/openmw/mwworld/cellpreloader.cpp:98 (openmw+0x0000014b7598)
#10 SceneUtil::WorkThread::run() /home/xyz/openmw/components/sceneutil/workqueue.cpp:134 (openmw+0x00000172c74e)
#11 OpenThreads::ThreadPrivateActions::StartThread(void*) <null> (libOpenThreads.so.21+0x00000000a2ba)
#12 <null> <null> (libtsan.so.0+0x00000002583b)
Previous write of size 4 at 0x7b2800145250 by thread T13:
#0 osg::Array::setBinding(osg::Array::Binding) /home/xyz/osg/include/osg/Array:189 (libosg.so.160+0x0000004b1174)
#1 osg::Geometry::setTexCoordArray(unsigned int, osg::Array*, osg::Array::Binding) /home/xyz/osg/src/osg/Geometry.cpp:247 (libosg.so.160+0x0000004a7504)
#2 osg::Geometry::setTexCoordArray(unsigned int, osg::Array*) /home/xyz/openmw-prefix/include/osg/Geometry:79 (openmw+0x0000016ec485)
#3 Terrain::ChunkManager::createChunk(float, osg::Vec2f const&, int, unsigned int) /home/xyz/openmw/components/terrain/chunkmanager.cpp:206 (openmw+0x0000018eeef6)
#4 Terrain::ChunkManager::getChunk(float, osg::Vec2f const&, int, unsigned int) /home/xyz/openmw/components/terrain/chunkmanager.cpp:47 (openmw+0x0000018ed28f)
#5 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:58 (openmw+0x0000018ea0f3)
#6 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:50 (openmw+0x0000018e9e90)
#7 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:51 (openmw+0x0000018e9f31)
#8 Terrain::TerrainGrid::cacheCell(Terrain::View*, int, int) /home/xyz/openmw/components/terrain/terraingrid.cpp:37 (openmw+0x0000018e9cb5)
#9 MWWorld::PreloadItem::doWork() /home/xyz/openmw/apps/openmw/mwworld/cellpreloader.cpp:98 (openmw+0x0000014b7598)
#10 SceneUtil::WorkThread::run() /home/xyz/openmw/components/sceneutil/workqueue.cpp:134 (openmw+0x00000172c74e)
#11 OpenThreads::ThreadPrivateActions::StartThread(void*) <null> (libOpenThreads.so.21+0x00000000a2ba)
#12 <null> <null> (libtsan.so.0+0x00000002583b)
Location is heap block of size 152 at 0x7b28001451e0 allocated by thread T4:
#0 operator new(unsigned long) <null> (libtsan.so.0+0x00000006f546)
#1 Terrain::BufferCache::getUVBuffer(unsigned int) /home/xyz/openmw/components/terrain/buffercache.cpp:191 (openmw+0x0000019c318d)
#2 Terrain::ChunkManager::createChunk(float, osg::Vec2f const&, int, unsigned int) /home/xyz/openmw/components/terrain/chunkmanager.cpp:206 (openmw+0x0000018eeed7)
#3 Terrain::ChunkManager::getChunk(float, osg::Vec2f const&, int, unsigned int) /home/xyz/openmw/components/terrain/chunkmanager.cpp:47 (openmw+0x0000018ed28f)
#4 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:58 (openmw+0x0000018ea0f3)
#5 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:50 (openmw+0x0000018e9e90)
#6 Terrain::TerrainGrid::buildTerrain(osg::Group*, float, osg::Vec2f const&) /home/xyz/openmw/components/terrain/terraingrid.cpp:50 (openmw+0x0000018e9e90)
#7 Terrain::TerrainGrid::cacheCell(Terrain::View*, int, int) /home/xyz/openmw/components/terrain/terraingrid.cpp:37 (openmw+0x0000018e9cb5)
#8 MWWorld::PreloadItem::doWork() /home/xyz/openmw/apps/openmw/mwworld/cellpreloader.cpp:98 (openmw+0x0000014b7598)
#9 SceneUtil::WorkThread::run() /home/xyz/openmw/components/sceneutil/workqueue.cpp:134 (openmw+0x00000172c74e)
#10 OpenThreads::ThreadPrivateActions::StartThread(void*) <null> (libOpenThreads.so.21+0x00000000a2ba)
#11 <null> <null> (libtsan.so.0+0x00000002583b)
Thread T2 (tid=8026, 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 SceneUtil::WorkQueue::WorkQueue(int) /home/xyz/openmw/components/sceneutil/workqueue.cpp:49 (openmw+0x00000172bf37)
#4 OMW::Engine::prepareEngine(Settings::Manager&) /home/xyz/openmw/apps/openmw/engine.cpp:469 (openmw+0x00000166d6a3)
#5 OMW::Engine::go() /home/xyz/openmw/apps/openmw/engine.cpp:663 (openmw+0x00000166f5dc)
#6 runApplication(int, char**) /home/xyz/openmw/apps/openmw/main.cpp:252 (openmw+0x00000164e5a2)
#7 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)
#8 main /home/xyz/openmw/apps/openmw/main.cpp:264 (openmw+0x00000164e69b)
Thread T13 (tid=8037, 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 SceneUtil::WorkQueue::WorkQueue(int) /home/xyz/openmw/components/sceneutil/workqueue.cpp:49 (openmw+0x00000172bf37)
#4 OMW::Engine::prepareEngine(Settings::Manager&) /home/xyz/openmw/apps/openmw/engine.cpp:469 (openmw+0x00000166d6a3)
#5 OMW::Engine::go() /home/xyz/openmw/apps/openmw/engine.cpp:663 (openmw+0x00000166f5dc)
#6 runApplication(int, char**) /home/xyz/openmw/apps/openmw/main.cpp:252 (openmw+0x00000164e5a2)
#7 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)
#8 main /home/xyz/openmw/apps/openmw/main.cpp:264 (openmw+0x00000164e69b)
Thread T4 (tid=8028, 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 SceneUtil::WorkQueue::WorkQueue(int) /home/xyz/openmw/components/sceneutil/workqueue.cpp:49 (openmw+0x00000172bf37)
#4 OMW::Engine::prepareEngine(Settings::Manager&) /home/xyz/openmw/apps/openmw/engine.cpp:469 (openmw+0x00000166d6a3)
#5 OMW::Engine::go() /home/xyz/openmw/apps/openmw/engine.cpp:663 (openmw+0x00000166f5dc)
#6 runApplication(int, char**) /home/xyz/openmw/apps/openmw/main.cpp:252 (openmw+0x00000164e5a2)
#7 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)
#8 main /home/xyz/openmw/apps/openmw/main.cpp:264 (openmw+0x00000164e69b)
SUMMARY: ThreadSanitizer: data race /home/xyz/osg/include/osg/Array:189 in osg::Array::setBinding(osg::Array::Binding)
ChunkManager::createChunk
is called by multiple threads on the same ChunkManager object. Inside, it uses mBufferCache.getUVBuffer(numVerts)
.
If multiple threads get same numVerts
they will retrieve the same osg::Vec2Array
object from the BufferCache
. On the first look this appears to be safe since the threads aren't writing to the buffer.
However, when the buffer passed in geometry->setTexCoordArray
, OSG will call setBinding
on the (shared) Array object here: https://github.com/OpenMW/osg/blob/ecedf3232c2f1b3b6a2f06f77ea37a9afb6a93f5/src/osg/Geometry.cpp#L247
setBinding
will assign to _binding
field of the Array object from multiple threads at the same time, resulting in a data race.