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