Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
New Contributor I
59 Views

Issues with std::weak_ptr<>, Compiler 19.0(2019 Update 5), 19.1 (2020), and Visual Studio 2019 16.4.4

There seems to be quite a serious issue with std::weak_ptr<> and Intel Compiler 19.0 and 19.1 with Visual Studio 2019.

The problem appears to be that the class _Ref_count_base, which includes the code

    _Atomic_counter_t _Uses  = 1;
    _Atomic_counter_t _Weaks = 1;

Does not appear to be initializing _Weaks to 1 ( when using Intel, not MSVC)

Run this simple program under the debugger and examine the values of _Weaks after the std::weak_ptr<int> has been constructed

Compiled with MSVC and with Intel. Debug at the return statement. You will see _Weaks=2 with MSVC but _Weaks=1 with Intel

 

int main()
{
    std::shared_ptr<int> aStrong = std::make_shared<int>(10);
    std::weak_ptr<int> aWeak(aStrong);

return 0;
}

0 Kudos
11 Replies
Highlighted
New Contributor I
59 Views

Example of how dangerous this

Example of how dangerous this is - the shared_ptr points to garbage after the weak_ptr goes out of scope.


What is happening is that since the weak_ptr _Weaks is initialized to 0  (not 1),  the weak_ptr goes out of scope, the _Weaks field is decremented to 0. This causes the base class _Ref_count_base to call _Delete_this() which deletes the structure shared by the std::shared_ptr<> and the std::weak_ptr<>. So when the std::shared_ptr<> is dereferenced it goes to find the pointer to the aTest object, it gets garbage from deleted memory.

 

 

 

#include <memory>
#include <iostream>
class atest
{
public:
    atest(int n):n_(n) {};
    virtual ~atest()
    {
        std::cout << "calling destructor" << std::endl;
    }
    int n_;
};
int main()
{
    std::shared_ptr<atest> aStrong = std::make_shared<atest>(10);
    {
        std::weak_ptr<atest> aWeak(aStrong);
    }
    std::cout << "should be 10: " << aStrong->n_ << std::endl;
    return 0;
}

0 Kudos
Highlighted
New Contributor I
59 Views

This may not have been

This may not have been encountered before as in previous versions of <memory> ( some versions prior to 16.4.4 Visual Studio 2019 version), the code looked like this

    _Atomic_counter_t _Uses;
    _Atomic_counter_t _Weaks;

protected:
    _Ref_count_base()
        : _Uses(1), _Weaks(1) // non-atomic initializations
    {}

Now, it looks like this

    _Atomic_counter_t _Uses  = 1;
    _Atomic_counter_t _Weaks = 1;

protected:
    constexpr _Ref_count_base() noexcept = default; // non-atomic initializations

 

 

0 Kudos
Highlighted
New Contributor I
59 Views

And to add insult to injury..

And to add insult to injury... even if you don't use weak_ptr<> then this bug will cause every single std::shared_ptr<> to a unique object to now leak an amount of memory equal to the sizeof() the _Ref_count_base (and derived) object.

Why? When a shared_ptr<> is destroyed it decrements _Uses and checks the _Uses count. If that is 0, the pointed-to-object is destroyed.So far, so good...

It then decrements _Weaks and checks if the _Weaks count==0. Sadly, this count will be -1 ( assuming no weak_ptr<>s) , not 0 so the _Ref_count_base will not call _Delete_this  which deallocates the _Ref_count_base and derived objects.

0 Kudos
Highlighted
New Contributor I
59 Views

This is the same bug as

This is the same bug as described in https://software.intel.com/en-us/forums/intel-c-compiler/topic/827586

And it STILL has not been fixed in 2020?

I see the problem is Release mode, not just Debug mode.

0 Kudos
Highlighted
Moderator
59 Views

Hi,

Hi,

We have verified this on Linux with icc/icpc version 19.1. We did not notice any issue. We are in the process of verifying this on Visual studio environment. We will get back to you once its done.

-Rahul

0 Kudos
Highlighted
New Contributor I
59 Views

Quote:Vaidya, Rahul (Intel)

Vaidya, Rahul (Intel) wrote:

Hi,

We have verified this on Linux with icc/icpc version 19.1. We did not notice any issue. We are in the process of verifying this on Visual studio environment. We will get back to you once its done.

-Rahul

Why are you wasting your time on Linux? There is no problem on Linux as the STL headers are different. This is ONLY a problem under Visual Studio 2019.

Andrew

 

0 Kudos
Highlighted
New Contributor I
59 Views

The "workaround" is to edit

The "workaround" is to edit <memory> in Visual Studio and change the code.

    //constexpr _Ref_count_base() noexcept = default; // non-atomic initializations
    _Ref_count_base():_Uses(1),_Weaks(1)
    {
    } // non-atomic initializations

0 Kudos
Highlighted
New Contributor I
59 Views

Intel Support ticket

Intel Support ticket #04526637

0 Kudos
Highlighted
Moderator
59 Views

Thanks for letting us know

Thanks for letting us know the ticket number. Our Engineer will work on it and then updates the ticket with new finding/info. 

0 Kudos
Highlighted
New Contributor I
60 Views

This bug means Intel Compiler

This bug means Intel Compiler 2020 cannot be with Visual Studio 2019 16.4.x to compile any C++ code uses std::weak_ptr<> and std::shared_ptr<> ( without hacking the <memory> header) . I would categorize that as a "show-stopper".

0 Kudos
Highlighted
New Contributor I
59 Views

This bug has been fixed in

This bug has been fixed in 2020 Update 1

0 Kudos