Hi Robert,

After upgrading to the latest OSG recently, I spotted a memory leak.
After some investigations, I found that the guilty was the revision
8400, which introduced a custom null stream as a replacement for
/dev/null. The code instantiates a custom streambuf (line 99: new
NullStreamBuffer()) and binds it to an ostream. This works well but
the NullStreamBuffer is never freed, resulting in a 60 bytes memory
leak when the program terminates.

The attached file fixes this by creating the custom streambuf on the
stack and passing a pointer to it to the ostream. I have tried it on
Windows XP SP3 + OSG rev 8647.

Another solution - which I have tried and works as well - would be
deriving the NullStreamBuffer from osg::Referenced and keeping a
static ref_ptr to it. It seems more complicated for no apparent
benefits so I went the stack route.

The question of why this memory leak is not reported when I run
"osgviewer cow.osg" remains a mystery to me - I suspect this is a
"feature" of Microsoft's debugging CRT. It would only show up in my
application as well as in a minimal sample using wxWidgets and OSG.
However, assuming that the ostream does not own the streambuf you pass
it (I could not find any evidence that it does) there is clearly a
leak.(*)

Regards

Thibault

(*) Somewhere on the page
http://www.slac.stanford.edu/comp/unix/gnu-info/iostream_3.html I have
found
"If you give the ostream a streambuf explicitly, using this
constructor, the sb is not destroyed (or deleted or closed) when the
ostream is destroyed."
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * OpenSceneGraph Public License for more details.
*/
#include <osg/Notify>
#include <string>
#include <stdlib.h>
#include <iostream>
#include <fstream>

using namespace std;

osg::NotifySeverity g_NotifyLevel = osg::NOTICE;

void osg::setNotifyLevel(osg::NotifySeverity severity)
{
    osg::initNotifyLevel();
    g_NotifyLevel = severity;
}


osg::NotifySeverity osg::getNotifyLevel()
{
    osg::initNotifyLevel();
    return g_NotifyLevel;
}


bool osg::initNotifyLevel()
{
    static bool s_NotifyInit = false;

    if (s_NotifyInit) return true;
    
    // g_NotifyLevel
    // =============

    g_NotifyLevel = osg::NOTICE; // Default value

    char* OSGNOTIFYLEVEL=getenv("OSG_NOTIFY_LEVEL");
    if (!OSGNOTIFYLEVEL) OSGNOTIFYLEVEL=getenv("OSGNOTIFYLEVEL");
    if(OSGNOTIFYLEVEL)
    {

        std::string stringOSGNOTIFYLEVEL(OSGNOTIFYLEVEL);

        // Convert to upper case
        for(std::string::iterator i=stringOSGNOTIFYLEVEL.begin();
            i!=stringOSGNOTIFYLEVEL.end();
            ++i)
        {
            *i=toupper(*i);
        }

        if(stringOSGNOTIFYLEVEL.find("ALWAYS")!=std::string::npos)          
g_NotifyLevel=osg::ALWAYS;
        else if(stringOSGNOTIFYLEVEL.find("FATAL")!=std::string::npos)      
g_NotifyLevel=osg::FATAL;
        else if(stringOSGNOTIFYLEVEL.find("WARN")!=std::string::npos)       
g_NotifyLevel=osg::WARN;
        else if(stringOSGNOTIFYLEVEL.find("NOTICE")!=std::string::npos)     
g_NotifyLevel=osg::NOTICE;
        else if(stringOSGNOTIFYLEVEL.find("DEBUG_INFO")!=std::string::npos) 
g_NotifyLevel=osg::DEBUG_INFO;
        else if(stringOSGNOTIFYLEVEL.find("DEBUG_FP")!=std::string::npos)   
g_NotifyLevel=osg::DEBUG_FP;
        else if(stringOSGNOTIFYLEVEL.find("DEBUG")!=std::string::npos)      
g_NotifyLevel=osg::DEBUG_INFO;
        else if(stringOSGNOTIFYLEVEL.find("INFO")!=std::string::npos)       
g_NotifyLevel=osg::INFO;
        else std::cout << "Warning: invalid OSG_NOTIFY_LEVEL set 
("<<stringOSGNOTIFYLEVEL<<")"<<std::endl;
 
    }

    s_NotifyInit = true;

    return true;

}

bool osg::isNotifyEnabled( osg::NotifySeverity severity )
{
    return severity<=g_NotifyLevel;
}

class NullStreamBuffer : public std::streambuf
{
    private:
    
        virtual streamsize xsputn (const char_type*, streamsize n)
        {
            return n;
        }
};

std::ostream& osg::notify(const osg::NotifySeverity severity)
{
    // set up global notify null stream for inline notify
    static NullStreamBuffer s_NotifyNulStreamBuffer;
    static std::ostream s_NotifyNulStream(&s_NotifyNulStreamBuffer);

    static bool initialized = false;
    if (!initialized) 
    {
        std::cerr<<""; // dummy op to force construction of cerr, before a 
reference is passed back to calling code.
        std::cout<<""; // dummy op to force construction of cout, before a 
reference is passed back to calling code.
        initialized = osg::initNotifyLevel();
    }

    if (severity<=g_NotifyLevel)
    {
        if (severity<=osg::WARN) return std::cerr;
        else return std::cout;
    }
    return s_NotifyNulStream;
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to