Skip to content

weak_ptr(weak_ptr const &) can segfault in the presence of virtual bases #40459

@Quuxplusone

Description

@Quuxplusone
Bugzilla Link 41114
Version trunk
OS All
CC @zygoloid

Extended Description

cat >test.cc <<EOF

#include <memory>
#include <stdio.h>

struct A { int i = 0; virtual ~A() {} };
struct B : public virtual A { char d[100000]; };

int main() {
    std::weak_ptr<B> p = std::shared_ptr<B>(new B);
    puts("hello world");
    std::weak_ptr<A> q = p;
}

EOF
clang++ -std=c++11 test.cc
./a.out

Segmentation fault

What's going on here is that the converting constructor weak_ptr(const weak_ptr&) is implemented as

weak_ptr<_Tp>::weak_ptr(shared_ptr<_Yp> const& __r,
                        typename enable_if<is_convertible<_Yp*, _Tp*>::value, __nat*>::type)
                         _NOEXCEPT
    : __ptr_(__r.__ptr_),     // LINE XXX
      __cntrl_(__r.__cntrl_)
{
    if (__cntrl_)
        __cntrl_->__add_weak();
}

When _Tp is a virtual base of _Yp, the conversion on line XXX generally needs to dereference __r.__ptr_ to compute the appropriate offset. This is fine if the weak_ptr stores a null pointer value, and it's fine if the weak_ptr is not-expired; but if the weak_ptr is expired (or empty) and stores a non-null pointer value, then we dereference into freed memory and segfault.

The solution adopted by both libstdc++ and MSVC is to implement this constructor as essentially

weak_ptr<_Tp>::weak_ptr(shared_ptr<_Yp> const& __r,
                        typename enable_if<is_convertible<_Yp*, _Tp*>::value, __nat*>::type)
                         _NOEXCEPT
    : weak_ptr(__r.lock())
{}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugzillaIssues migrated from bugzillaconfirmedVerified by a second partygood first issuehttps://github.com/llvm/llvm-project/contributelibc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions