-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviews.apache.org/r/14555/
-----------------------------------------------------------

Review request for qpid, Gordon Sim and Kim van der Riet.


Bugs: https://issues.apache.org/jira/browse/QPID-5214
    
https://issues.apache.org/jira/browse/https://issues.apache.org/jira/browse/QPID-5214


Repository: qpid


Description
-------

mrg::msgstore::MessageStoreImpl::enqueue method calls:

..
if (queue) {
boost::intrusive_ptr<DataTokenImpl> dtokp(new DataTokenImpl);
dtokp->addRef();
..
(where in further code calls executed, an exception is raised within the scope 
of dtokp life)

Apparently, boost library has a limitation with throwing exceptions where it 
forgets to remove some reference to the object, causing delete is not executed 
when intrusive_ptr variable is gone. See my reproducer below, independend on 
qpid/store code.

Therefore, to workaround it, let release the dtokp manually just before 
throwing the exception. But I don't fully like adding new parameter to 
handleIoResult method (and not sure with re-casting dtokp from data_tok* to 
DataTokenImpl* is done in proper way).

Reproducer of boost::intrusive_ptr limitation when throwing exception: let run 
below program via valgrind, first as is (direct memory loss), and then with 
"dtokp->release();" line uncommented (no direct memory loss).

#include <iostream>
#include <boost/intrusive_ptr.hpp>
#include <boost/utility.hpp>
#include <boost/detail/atomic_count.hpp>

class RefCounted : public boost::noncopyable {
    mutable boost::detail::atomic_count count;

public:
    RefCounted() : count(0) {}
    void addRef() const { ++count; }
    void release() const { if (--count==0) released(); }
    long refCount() { return count; }

protected:
    virtual ~RefCounted() {};
    // Allow subclasses to over-ride behavior when refcount reaches 0.
    virtual void released() const { delete this; }
};

// intrusive_ptr support.
inline void intrusive_ptr_add_ref(const RefCounted* p) { p->addRef(); }
inline void intrusive_ptr_release(const RefCounted* p) { p->release(); }


class DataTokenImpl : public RefCounted
{
  public:
    DataTokenImpl() {}
    ~DataTokenImpl() {}
};

void enqueue_data_record(const DataTokenImpl* dtokp) {
//  dtokp->release();
  throw 20;
}

int local()
{
  try {
    boost::intrusive_ptr<DataTokenImpl> dtokp(new DataTokenImpl);
    dtokp->addRef();
    enqueue_data_record(dtokp.get());
  }
  catch (int e) {
    std::cout << "local: caught exception " << e << std::endl;
    throw;
  }
  return 0;
}

int main(void)
{
  try {
    local();
  }
  catch (int e) {
    std::cout << "main: caught exception " << e << std::endl;
  }
  return 0;
}


Diffs
-----

  /trunk/qpid/cpp/src/qpid/legacystore/JournalImpl.h 1528730 
  /trunk/qpid/cpp/src/qpid/legacystore/JournalImpl.cpp 1528730 

Diff: https://reviews.apache.org/r/14555/diff/


Testing
-------

Valgrind used for reproducer returned no memory related problems, automated 
tests passed.


Thanks,

Pavel Moravec

Reply via email to