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

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;
}

附件大小
下载image/png Intel.png26.95 KB
下载image/png MSVC.png28.6 KB
12 帖子 / 0 全新

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;
}


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

 

 


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.


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.


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


引文:

Vaidya, Rahul (Intel) 写道:

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

 


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


Intel Support ticket #04526637


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


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".


This bug has been fixed in 2020 Update 1

发表评论

登录添加评论。 还不是成员? 立即加入