Skip to content

Commit b861457

Browse files
authored
[libc++] Fix a segfault in weak_ptr(const weak_ptr<Y>&) (#67956)
Fixes #40459
1 parent 457f582 commit b861457

File tree

2 files changed

+70
-8
lines changed

2 files changed

+70
-8
lines changed

libcxx/include/__memory/shared_ptr.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,11 +1727,11 @@ template<class _Yp, __enable_if_t<__compatible_with<_Yp, _Tp>::value, int> >
17271727
inline
17281728
weak_ptr<_Tp>::weak_ptr(weak_ptr<_Yp> const& __r)
17291729
_NOEXCEPT
1730-
: __ptr_(__r.__ptr_),
1731-
__cntrl_(__r.__cntrl_)
1730+
: __ptr_(nullptr),
1731+
__cntrl_(nullptr)
17321732
{
1733-
if (__cntrl_)
1734-
__cntrl_->__add_weak();
1733+
shared_ptr<_Yp> __s = __r.lock();
1734+
*this = weak_ptr<_Tp>(__s);
17351735
}
17361736

17371737
template<class _Tp>
@@ -1749,11 +1749,12 @@ template<class _Yp, __enable_if_t<__compatible_with<_Yp, _Tp>::value, int> >
17491749
inline
17501750
weak_ptr<_Tp>::weak_ptr(weak_ptr<_Yp>&& __r)
17511751
_NOEXCEPT
1752-
: __ptr_(__r.__ptr_),
1753-
__cntrl_(__r.__cntrl_)
1752+
: __ptr_(nullptr),
1753+
__cntrl_(nullptr)
17541754
{
1755-
__r.__ptr_ = nullptr;
1756-
__r.__cntrl_ = nullptr;
1755+
shared_ptr<_Yp> __s = __r.lock();
1756+
*this = weak_ptr<_Tp>(__s);
1757+
__r.reset();
17571758
}
17581759

17591760
template<class _Tp>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <memory>
10+
11+
// weak_ptr
12+
13+
// template<class Y> weak_ptr(const weak_ptr<Y>& r);
14+
// template<class Y> weak_ptr(weak_ptr<Y>&& r);
15+
//
16+
// Regression test for https://github.com/llvm/llvm-project/issues/40459
17+
// Verify that these constructors never attempt a derived-to-virtual-base
18+
// conversion on a dangling weak_ptr.
19+
20+
#include <cassert>
21+
#include <cstring>
22+
#include <memory>
23+
#include <utility>
24+
25+
#include "test_macros.h"
26+
27+
struct A {
28+
int i;
29+
virtual ~A() {}
30+
};
31+
struct B : public virtual A {
32+
int j;
33+
};
34+
struct Deleter {
35+
void operator()(void*) const {
36+
// do nothing
37+
}
38+
};
39+
40+
int main(int, char**) {
41+
#if TEST_STD_VER >= 11
42+
alignas(B) char buffer[sizeof(B)];
43+
#else
44+
std::aligned_storage<sizeof(B), std::alignment_of<B>::value>::type buffer;
45+
#endif
46+
B* pb = ::new ((void*)&buffer) B();
47+
std::shared_ptr<B> sp = std::shared_ptr<B>(pb, Deleter());
48+
std::weak_ptr<B> wp = sp;
49+
sp = nullptr;
50+
assert(wp.expired());
51+
52+
// Overwrite the B object with junk.
53+
std::memset(&buffer, '*', sizeof(buffer));
54+
55+
std::weak_ptr<A> wq = wp;
56+
assert(wq.expired());
57+
std::weak_ptr<A> wr = std::move(wp);
58+
assert(wr.expired());
59+
60+
return 0;
61+
}

0 commit comments

Comments
 (0)