Opened 21 years ago

Closed 19 years ago

#5 closed Bugs (Fixed)

shared_ptr and self-owning objects

Reported by: nobody Owned by: Peter Dimov
Milestone: Component: smart_ptr
Version: None Severity:
Keywords: Cc:

Description

Consider following program:

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

class foo {
        public: 
                foo(): m_self(this) { std::cout << "foo
constructor\n"; }
                ~foo() { std::cout << "foo
destructor\n"; }
                void suicide() { m_self.reset(0); }
        private:
                boost::shared_ptr<foo> m_self;
};              

int main() {
        foo *foo_ptr = new foo;
        foo_ptr->suicide();
}       

When linked with Electric Fence this code fails. This
code invokes undefined behavior in reset method of
shared_ptr: when line if (--*pn == 0) {
checked_delete(px); } executes shared_ptr object gets
destroyed and line *pn = 1 acceses already freed
memory.

Why use m_self? 

foo's clients share foo by keeping shared_ptr to it.
foo handles some asynchronous event which may render
foo unneeded to itself (network connection close, for
example), but it still may be needed to clients if any.
OTOH, if no clients use foo at the time of the event
then foo needs to destroy itself. This situation is
best modeled with keeping shared_ptr in foo and letting
foo to reset it when foo thinks it's mission is
complete.

The problem with shared_ptr can be solved with small
modification to reset
method:

void reset(T* p=0) {
    T *old_px = px;
    if ( px == p ) return;  // fix: self-assignment
safe
    px = p;
    if (--*pn == 0) {
        *pn = 1;
        checked_delete(old_px);
    }
    else { // allocate new reference counter
        try { pn = new long(1); }  // fix: prevent leak
if new throws
        catch (...) {
            ++*pn;  // undo effect of --*pn above to
meet effects guarantee
            px = old_px; // undo effect of px = p above
            checked_delete(p);
            throw;
        } // catch
    } // allocate new reference counter
} // reset

operator=(const shared_ptr&) and
operator=(std::auto_ptr&) have the same problem and fix
is very similiar. 



Change History (2)

comment:1 by darinadler, 21 years ago

Logged In: YES 
user_id=243358

Peter Dimov is planning to fix this.

comment:2 by Peter Dimov, 19 years ago

Status: assignedclosed
Note: See TracTickets for help on using tickets.