I just wanted to share with you a test file used to verify how dangerous is
the current use of boost::intrusive_ptr by Gnash.

Basically, the intrusive_ptr chain must NOT be broken, or premature deletion,
with consequent memory corruption will happen.

See this bug for an examplar sympthom: https://savannah.gnu.org/bugs/?18675
Note that the bug can reveal itself much later then the time in which it is
introduced, so it's worth inspecting for possible early-catcher solutions.

The attached testcase contains a "forbid-deletion" mechanism making debugging
easier. We might want to add this to gnash as well when facing similar problems
or rething the whole smart pointers model. On a side-note, it seems that 
intrusive_ptr
will be deprecated by boost dev team.

Comments welcome.

--strk;

 ()   ASCII Ribbon Campaign
 /\   Keep it simple! 

//
// This test code shows a dangerous aspect of boost::intrusive pointer.
// I belive this is the problem Gnash currently has with player2.swf (google 
player)
// and others.
//

#include <iostream>
#include <boost/intrusive_ptr.hpp>

using namespace boost;
using namespace std;


// boost required helper funx
template <class T> void intrusive_ptr_add_ref(T* o) { o->add_ref(); }
template <class T> void intrusive_ptr_release(T* o) { o->drop_ref(); }

//
// This is a ref-counted class, equivalent
// to gnash::ref_counted, which is the base
// of most Gnash resources
//
class Base {

        int refs;

        // This flag is here to help debugging,
        // if false, the destructor will abort
        bool destruction_allowed;

public:

        // Construct the base with an initial refcount == 0
        // and destruction forbidden
        Base()
                :
                refs(0),
                destruction_allowed(false)
        {
                cout << this << ") Base constructed" << endl;
        }

        void add_ref() {
                ++refs;
                cout << this << ") Base ref added (" << refs << ")" << endl;
        }

        void drop_ref() {
                assert(refs>0);
                cout << this << ") Base released (" << refs-1 << ")" << endl;
                if ( ! --refs ) delete this;
        }

        ~Base() {
                assert(destruction_allowed);
                assert(refs==0);
                cout << this << ") Base deleted " << endl;
        }

        // Call this when you think deleting this object is fine
        void allowDestruction() { destruction_allowed = true; }

};

// This function is dangerous because it stores the Base pointer
// argument into an intrusive_ptr. IFF the given Base pointer
// does NOT have a ref_count > 0, it will be deleted when this
// function exits.
// Probably a good approach is adding an assertion at the start
// of the function stating that number of refs in given arg is > 0
// This would likely help debuggin.
void
dangerous_func(Base* arg)
{
        cout << "  dangerous_func start" << endl;
        intrusive_ptr<Base> b = arg;
        cout << "  dangerous_func end" << endl;
}

// Calling this function will make the code abort
Base* 
gimme_base()
{
        Base* b = new Base;
        dangerous_func(b);
        return b;

}

// Calling this function will make the code abort
Base* 
gimme_base2()
{
        intrusive_ptr<Base> b = new Base;
        dangerous_func(b.get());
        return b.get();

}

// This is the *only* safe function, in that it returns
// the pointer wrapped into an intrusive_ptr
intrusive_ptr<Base>
safe_gimme_base()
{
        intrusive_ptr<Base> safe = new Base;
        dangerous_func(safe.get());
        return safe.get();

}

int
main()
{
        // Fails - gimme_base doesn't use intrusive_ptr at all
        //intrusive_ptr<Base> b = gimme_base();

        // Fails - gimme_base2 breaks the intrusive_ptr chain
        //intrusive_ptr<Base> b = gimme_base2();

        // Fails - the temporary intrusive_ptr returned is immediately deleted
        //Base* b = safe_gimme_base().get();

        // Succeeds
        intrusive_ptr<Base> b = safe_gimme_base();

        b->allowDestruction();
}
_______________________________________________
Gnash-dev mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/gnash-dev

Reply via email to