// // 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 #include using namespace boost; using namespace std; // boost required helper funx template void intrusive_ptr_add_ref(T* o) { o->add_ref(); } template 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 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 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 safe_gimme_base() { intrusive_ptr safe = new Base; dangerous_func(safe.get()); return safe.get(); } int main() { // Fails - gimme_base doesn't use intrusive_ptr at all //intrusive_ptr b = gimme_base(); // Fails - gimme_base2 breaks the intrusive_ptr chain //intrusive_ptr b = gimme_base2(); // Fails - the temporary intrusive_ptr returned is immediately deleted //Base* b = safe_gimme_base().get(); // Succeeds intrusive_ptr b = safe_gimme_base(); b->allowDestruction(); }