|
Boost : |
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2020-07-31 13:11:17
On 2020-07-31 15:56, Andrey Semashev wrote:
> 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.
I should note that in the code samples above I'm ignoring the mismatch
between `operator new` that is used to allocate objects and `std::free`
that rcgc_shared_ptr uses to free memory. That is another bug, of course.
>> 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