Boost logo

Boost :

From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2020-07-31 12:56:18


Please, don't top-post. Our discussion guidelines are described here:

https://www.boost.org/community/policy.html

On 2020-07-31 13:06, 逸霖 杨 via Boost wrote:
> Hi Andrey,
> Thanks for repaid response.
>
> It is freeing the memory at last decrement, but not immediately.
>
> It frees memory when all related objects’ reference count are decreased to zero.

Yes, it frees memory when the reference count becomes zero. But it
*destroys* the object (i.e. calls its destructor) earlier, before the
reference count is zero.

> void Dispose() {
> if (this->_ptr != nullptr) {
> PTR* _ptr = this->_ptr;
> this->_ptr = nullptr;
> _ptr->~PTR();

                ^^^ here ^^^

> RelRef(_ptr);
> }
> }

> As above, dispose method calls its pointing object’s destructor, but not free that object with free(ptr) function,

After the destructor call, the object no longer exists, regardless of
whether the memory it used to be placed in is freed or not.

Case 1:

   struct A
   {
     unsigned int x = 0u;

     ~A() { x = 0xBAADF00D; }
   };

   rcgc_shared_ptr< A > p1;
   {
     rcgc_shared_ptr< A > p2(new A());
     p1 = p2;
     std::cout << p1->x << std::endl;
   }
   std::cout << p1->x << std::endl; // (1)

The above is a bug because (1) accesses the object A after its
destruction. If A::x was, say a unique_ptr, it would be null or pointing
to already freed memory.

Case 2 (which follows from Case 1)

   struct B;

   struct A
   {
     rcgc_shared_ptr< B > m_b;
     std::string m_x;

     ~A() { std::cout << m_b->m_x << std::endl; }
   };

   struct B
   {
     rcgc_shared_ptr< A > m_a;
     std::string m_x;

     ~B() { std::cout << m_a->m_x << std::endl; }
   };

   rcgc_shared_ptr< A > p(new A());
   p->m_b.reset(new B());
   p->m_b->m_a = p;

When p gets destroyed, it will destroy the object A, even though it is
still referenced by B::m_a. When A::m_b is destroyed, it will call ~B,
which will access A::m_x, which is already destroyed.

> If you have Visual Studio and run the code which detects memory leak with
> #ifdef _WIN32
> _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
> #endif
>
> You will see no memory leak at all.

This check only shows that no memory is leaked. The problem here is not
a memory leak but incorrect memory access (potential use-after-destory
and use-after-free).


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk