Hi,

We recently got a strange crash behavior in our software. We were fixing a 
piece of code that caused GL_ERRORS on some platforms. When we had fixed this, 
a new bug surfaced in a completely different part of the code base. It was code 
that had worked for years, but suddenly it started to make our software crash. 
I was able to solve the problem, but I had problem understanding why it started 
to crash all out of a sudden. So I tried to reduce the bug to a smaller working 
set.

The crash results from a null pointer exception in operator() inside 
TemplateAttributeDispatch in ArrayDispachers.cpp.

See attached example for code that crashes when the variable:
useCrashProneWayOfSettingVertexColor is set to TRUE.

At first I though the problem was that we had multiple geometry sharing the 
same vertex color array. But that was not the problem. The problem was the way 
we changed the colors in the array. The old (and previously working) way of 
doing it was to use a node callback on the geode and in that callback clear and 
then fill the array with new values. (But this is the version that started to 
crash). So we changed the callback to iterate over the color array and changing 
the values instead. 

But I still have a bit of a problem with understanding why the first 
alternative would not work? Clearing and refilling the color array inside a 
node callback should be safe, but apparently not?

/Björn

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=59617#59617



#include <osg/Geometry>
#include <osg/PositionAttitudeTransform>
#include <osgViewer/Viewer>

#include <ctime>

class ColorCallback : public osg::NodeCallback {
public:
	ColorCallback()  {};
	virtual void operator() (osg::Node* node, osg::NodeVisitor* nv) {
		osg::ref_ptr<osg::Geode> geode = node->asGeode();
		if (geode) {
			osg::ref_ptr<osg::Geometry> geometry = geode->getDrawable(0)->asGeometry();
			if (geometry) {
				time_t currentTime;
				time(&currentTime);
				int colorId = currentTime % 3;
				osg::Vec4 color = osg::Vec4(1.0, 1.0, 1.0, 1.0);
				if (colorId == 0) {
					color = osg::Vec4(1.0, 0.0, 0.0, 1.0);
				} else if (colorId == 1) {
					color = osg::Vec4(0.0, 1.0, 0.0, 1.0);
				} else {
					color = osg::Vec4(0.0, 0.0, 1.0, 1.0);
				
				}

				osg::ref_ptr<osg::Vec4Array> colorArray = dynamic_cast<osg::Vec4Array*>(geometry->getColorArray());
				
				if (colorArray) {
					// Change below variable to toggle between working and crash prone version
					bool useCrashProneWayOfSettingVertexColor = true;
					if (useCrashProneWayOfSettingVertexColor) {
						colorArray->clear();
						colorArray->push_back(color);
						geometry->setColorArray(colorArray);
						geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
						colorArray->dirty();
					} else {
						for(osg::Vec4Array::iterator cIt = colorArray->begin(); cIt != colorArray->end(); ++cIt) {
							(*cIt) = color;
						}

					}
				}
			}
		}
		
		traverse(node, nv);
	}
private:
};


int main( int argc, char **argv ) {
	osg::ArgumentParser arguments(&argc,argv);
	osg::ref_ptr<osg::Vec4Array> colorArray1 = new osg::Vec4Array;
	colorArray1->push_back(osg::Vec4(0.0, 1.0, 0.0, 1.0));

	osg::ref_ptr<osg::Vec4Array> colorArray2 = new osg::Vec4Array;
	colorArray2->push_back(osg::Vec4(0.0, 1.0, 0.0, 1.0));

	osg::ref_ptr<osg::Geometry> geometry1 = new osg::Geometry;
	osg::ref_ptr<osg::Geometry> geometry2 = new osg::Geometry;

	osg::ref_ptr<osg::Vec3Array> vertexArray1 = new osg::Vec3Array;
	osg::ref_ptr<osg::Vec3Array> vertexArray2 = new osg::Vec3Array;

	osg::ref_ptr<osg::Vec3Array> normalArray1 = new osg::Vec3Array;
	osg::ref_ptr<osg::Vec3Array> normalArray2 = new osg::Vec3Array;

	vertexArray1->push_back(osg::Vec3(0.0, 0.0, 0.0));
	vertexArray1->push_back(osg::Vec3(1.0, 0.0, 0.0));
	vertexArray1->push_back(osg::Vec3(1.0, 0.0, 1.0));
	vertexArray1->push_back(osg::Vec3(0.0, 0.0, 1.0));

	normalArray1->push_back(osg::Vec3(0.0, -1.0, 0.0));

	vertexArray2->push_back(osg::Vec3(0.0, 0.0, 0.0));
	vertexArray2->push_back(osg::Vec3(1.0, 0.0, 0.0));
	vertexArray2->push_back(osg::Vec3(0.5, 0.0, 1.0));

	normalArray2->push_back(osg::Vec3(0.0, -1.0, 0.0));
	
	geometry1->setVertexArray(vertexArray1);
	geometry1->setNormalArray(normalArray1);
	geometry1->setNormalBinding(osg::Geometry::BIND_OVERALL);
	geometry1->setColorArray(colorArray1);
	geometry1->setColorBinding(osg::Geometry::BIND_OVERALL);
	geometry1->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,0,vertexArray1->size()));
	geometry1->setUseDisplayList(false);
	geometry1->setUseVertexBufferObjects(true);

	geometry2->setVertexArray(vertexArray2);
	geometry2->setNormalArray(normalArray2);
	geometry2->setNormalBinding(osg::Geometry::BIND_OVERALL);
	geometry2->setColorArray(colorArray2);
	geometry2->setColorBinding(osg::Geometry::BIND_OVERALL);
	geometry2->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,0,vertexArray2->size()));
	geometry2->setUseDisplayList(false);
	geometry2->setUseVertexBufferObjects(true);

	osg::ref_ptr<osg::Geode> geode1 = new osg::Geode;
	geode1->addDrawable(geometry1);
	geode1->setUpdateCallback(new ColorCallback());
	geode1->setDataVariance(osg::Object::DYNAMIC);

	osg::ref_ptr<osg::Geode> geode2 = new osg::Geode;
	geode2->addDrawable(geometry2);
	geode2->setUpdateCallback(new ColorCallback());
	geode2->setDataVariance(osg::Object::DYNAMIC);

	osg::ref_ptr<osg::Group> root = new osg::Group;

	osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new osg::PositionAttitudeTransform;
	pat1->setPosition(osg::Vec3(1.0, 0.0, 0.0));
	pat1->addChild(geode1);

	osg::ref_ptr<osg::PositionAttitudeTransform> pat2 = new osg::PositionAttitudeTransform;
	pat2->setPosition(osg::Vec3(-1.0, 0.0, 0.0));
	pat2->addChild(geode2);

	root->addChild(pat1);
	root->addChild(pat2);
	
	osgViewer::Viewer viewer(arguments);
	viewer.setSceneData(root);
	return viewer.run();
}

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

Reply via email to