Hi,

Here is code to reproduce crash:

<code>
#include <osgDB/ReadFile>
#include <OpenThreads/Mutex>
#include <OpenThreads/Thread>
#include <OpenThreads/Condition>

static OpenThreads::Condition s_cond;
static OpenThreads::Mutex s_mtx;

class ReadThread : public OpenThreads::Thread
{
public:
  ReadThread() {}

  void run()
  {
    {
      OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mtx);
      s_cond.wait(&s_mtx);
    }
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg");
  }
};

int main()
{
  ReadThread t1, t2;
  t1.start();
  t2.start();

//  OpenThreads::Thread::microSleep(500);

  {
    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mtx);
    s_cond.broadcast();
  }

  t1.join();
  t2.join();
  return 0;
}
</code>

To reproduce you can use this script:
<code>
#!/usr/bin/env bash

while(true); do
        ./test
done
</code>

But while testing fix I have new crash at:
ntdll!RtlReportCriticalFailure+0x62
ntdll!RtlpReportHeapFailure+0x26
ntdll!RtlpHeapHandleError+0x12
ntdll!RtlpLogHeapFailure+0xa4
ntdll!RtlpAnalyzeHeapFailure+0x3a8
ntdll!RtlpFreeHeap+0x141f
ntdll!RtlFreeHeap+0x1a6
kernel32!HeapFree+0xa
MSVCR90!free+0x1c
MSVCP90!std::basic_string<char,std::char_traits<char>,std::allocator<char>
MSVCP90!std::basic_string<char,std::char_traits<char>,std::allocator<char>
MSVCP90!std::operator+<char,std::char_traits<char>,std::allocator<char>
osg92_osgDB!osgDB::Registry::createLibraryNameForExtension+0x34b
osg92_osgDB!osgDB::Registry::createLibraryNameForFile+0x42
osg92_osgDB!osgDB::Registry::read+0x1608
osg92_osgDB!osgDB::Registry::readImplementation+0x34c
osg92_osgDB!osgDB::Registry::readNodeImplementation+0x6a
osg92_osgDB!osgDB::Registry::readNode+0xfc
osg92_osgDB!osgDB::readNodeFile+0x4e
dotosgcrash!ReadThread::run+0x79

code:
std::string Registry::createLibraryNameForExtension(const std::string& ext)
{
    std::string lowercase_ext;
    for(std::string::const_iterator sitr=ext.begin();
        sitr!=ext.end();
        ++sitr)
    {
        lowercase_ext.push_back(tolower(*sitr));
    }

    ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext);
if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second);

#if defined(OSG_JAVA_BUILD)
static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java");
#else
static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");
#endif
[..]

same design:
static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");

Mikhail.

04.06.2012 13:17, Mikhail I. Izmestev написал:
Hi Robert,

It is hard to reproduce this problem (as any thread safety problem) in
same state as previous.

I have another crash with same problem at:
ntdll!RtlEnterCriticalSection+0x6
ot12_OpenThreads!OpenThreads::Mutex::lock+0xe
osgdb_deprecated_osg!initGLNames+0x66
osgdb_deprecated_osg!StateSet_readLocalData+0x4f
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x9eb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x28
osgdb_deprecated_osg!Node_readLocalData+0x349
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_osg!OSGReaderWriter::readNode+0xfe
osgdb_osg!OSGReaderWriter::readNode+0x31c
osg80_osgDB!osgDB::Registry::ReadNodeFunctor::doRead+0x28
osg80_osgDB!osgDB::Registry::read+0x5e4
osg80_osgDB!osgDB::Registry::readImplementation+0x34c
osg80_osgDB!osgDB::Registry::readNodeImplementation+0x6a
osg80_osgDB!osgDB::Registry::readNode+0xfc
osg80_osgDB!osgDB::readNodeFile+0x4e

crashed code:
int Mutex::lock() {
Win32MutexPrivateData *pd =
static_cast<Win32MutexPrivateData*>(_prvData);

#ifdef USE_CRITICAL_SECTION

// Block until we can take this lock.
EnterCriticalSection( &(pd->_cs) ); <<<<<<<<<<<< CRASH HERE

return 0;
[...]

pd->_cs == NULL

in this case problem at
void initGLNames()
{
static bool first_time = true;
if (!first_time) return;

static OpenThreads::Mutex s_initGLNames;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_initGLNames);

[...]

There is lot of other places with same design:
AnimationPath.cpp:201: static osg::ref_ptr<osg::AnimationPath> s_path =
new osg::AnimationPath;
CoordinateSystemNode.cpp:48: static ref_ptr<EllipsoidModel>
s_ellipsoidModel = new EllipsoidModel;
Drawable.cpp:30: static ref_ptr<StateSet> s_drawstate = new osg::StateSet;
Node.cpp:77: static ref_ptr<StateSet> s_drawstate = new osg::StateSet;
Node.cpp:85: static ref_ptr<NodeCallback> s_nodecallback = new
osg::NodeCallback;
NodeCallback.cpp:31: static osg::ref_ptr<NodeCallback> s_nc = new
NodeCallback;
OccluderNode.cpp:30: static ref_ptr<ConvexPlanarOccluder> s_occluder =
new ConvexPlanarOccluder;
Sequence.cpp:26:static bool Sequence_matchLoopMode(const char* str,
Sequence.cpp:45:static const char*
Sequence_getLoopMode(Sequence::LoopMode mode)
Sequence.cpp:57:static bool Sequence_matchSeqMode(const char* str,
Sequence.cpp:76:static const char*
Sequence_getSeqMode(Sequence::SequenceMode mode)
StateAttribute.cpp:32: static ref_ptr<StateAttributeCallback> s_callback
= new osg::StateAttributeCallback;
StateSet.cpp:80: static bool first_time = true;
StateSet.cpp:83: static OpenThreads::Mutex s_initGLNames;
StateSet.cpp:362: static ref_ptr<StateSet::Callback> s_callback = new
osg::StateSet::Callback;
Uniform.cpp:212: static ref_ptr<Uniform::Callback> s_callback = new
osg::Uniform::Callback;

Mikhail.

04.06.2012 12:44, Robert Osfield написал:
Hi Mikhail,

I have moved the static into the global scope of the
osgWrappers/deprecated-dotosg/Drawable.cpp, file attached, could try
it out?

Robert.

On 2 June 2012 11:12, Mikhail I. Izmestev<izmmish...@gmail.com> wrote:
Hi,

I noticed crashing in dotosg wrappers when try to use
osgDB::readNodeFile
from multiple threads.
Crash occurs when I try to load .osg file from two threads.

For example callstack of crashed thread:
osg80_osgDB!concrete_wrapper::matches+0x4
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x527

osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObjectOfType+0x28
osgdb_deprecated_osg!Drawable_readLocalData+0xa1
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readDrawable+0xe1
osgdb_deprecated_osg!Geode_readLocalData+0x90
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_deprecated_osg!Group_readLocalData+0x71
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_deprecated_osg!Group_readLocalData+0x71
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_osg!OSGReaderWriter::readNode+0xfe
osgdb_osg!OSGReaderWriter::readNode+0x31c
osg80_osgDB!osgDB::Registry::ReadNodeFunctor::doRead+0x28
osg80_osgDB!osgDB::Registry::read+0x5e4
osg80_osgDB!osgDB::Registry::readImplementation+0x34c
osg80_osgDB!osgDB::Registry::readNodeImplementation+0x6a
osg80_osgDB!osgDB::Registry::readNode+0xfc
osg80_osgDB!osgDB::readNodeFile+0x4e
[...]

second thread callstack:
msvcp90!std::basic_istream<char,std::char_traits<char>
msvcp90!std::basic_istream<char,std::char_traits<char>
osg80_osgDB!osgDB::FieldReader::_readField+0x3f8
osg80_osgDB!osgDB::FieldReaderIterator::field+0x19d
osgdb_deprecated_osg!Array_readLocalData+0xbfb
osgdb_deprecated_osg!Geometry_readLocalData+0x991
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readDrawable+0xe1
osgdb_deprecated_osg!Geode_readLocalData+0x90
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_deprecated_osg!Group_readLocalData+0x71
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_deprecated_osg!Group_readLocalData+0x9a
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_deprecated_osg!Group_readLocalData+0x9a
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_deprecated_osg!Group_readLocalData+0x71
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readObject+0x8fb
osg80_osgDB!osgDB::DeprecatedDotOsgWrapperManager::readNode+0xe1
osgdb_osg!OSGReaderWriter::readNode+0xfe
osgdb_osg!OSGReaderWriter::readNode+0x31c
osg80_osgDB!osgDB::Registry::ReadNodeFunctor::doRead+0x28
osg80_osgDB!osgDB::Registry::read+0x5e4
osg80_osgDB!osgDB::Registry::readImplementation+0x34c
osg80_osgDB!osgDB::Registry::readNodeImplementation+0x6a
osg80_osgDB!osgDB::Registry::readNode+0xfc
osg80_osgDB!osgDB::readNodeFile+0x4e
[...]

code:
struct concrete_wrapper: basic_type_wrapper
{
virtual ~concrete_wrapper() {}
concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
bool matches(const osg::Object *proto) const
{
return myobj_->isSameKindAs(proto);<<<<<<<<<<<<<<<<<CRASH
HERE<<<<<<<
}
const osg::Object *myobj_;
};

crash occurs because myobj_ is NULL.

myobj_ passed from osgdb_deprecated_osg!Drawable_readLocalData as
s_drawstate

bool Drawable_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;

Drawable& drawable = static_cast<Drawable&>(obj);

static ref_ptr<StateSet> s_drawstate = new osg::StateSet;
if (StateSet* readState =
static_cast<StateSet*>(fr.readObjectOfType(*s_drawstate)))
{
drawable.setStateSet(readState);
iteratorAdvanced = true;
}
[...]


so problem is in
static ref_ptr<StateSet> s_drawstate = new osg::StateSet;

MSVC 2008 x64 compiler (maybe gcc too) generate this code as:

static bool s_drawstate_init = false;
static ref_ptr<StateSet> s_drawstate = NULL;

bool Drawable_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;

Drawable& drawable = static_cast<Drawable&>(obj);

if(!s_drawstate_init)
{
s_drawstate_init = true;
s_drawstate = new osg::StateSet;
}

if (StateSet* readState =
static_cast<StateSet*>(fr.readObjectOfType(*s_drawstate)))
{
drawable.setStateSet(readState);
iteratorAdvanced = true;
}
[...]


and this code is not thread safe as you can see.

Possible solution is to move static variables to global scope to
avoid lazy
initialization.


Mikhail.
_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org



_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org



_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to