[libcxx-commits] [libcxx] [libc++] Fix a segfault in weak_ptr(const weak_ptr<Y>&) (PR #67956)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 2 00:36:57 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

<details>
<summary>Changes</summary>

Fixes https://github.com/llvm/llvm-project/issues/40459

---
Full diff: https://github.com/llvm/llvm-project/pull/67956.diff


2 Files Affected:

- (modified) libcxx/include/__memory/shared_ptr.h (+9-8) 
- (added) libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.const/pr40459.pass.cpp (+61) 


``````````diff
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 6be2f22184590ae..33a1b95a31ddbd5 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -1727,11 +1727,11 @@ template<class _Yp, __enable_if_t<__compatible_with<_Yp, _Tp>::value, int> >
 inline
 weak_ptr<_Tp>::weak_ptr(weak_ptr<_Yp> const& __r)
          _NOEXCEPT
-    : __ptr_(__r.__ptr_),
-      __cntrl_(__r.__cntrl_)
+    : __ptr_(nullptr),
+      __cntrl_(nullptr)
 {
-    if (__cntrl_)
-        __cntrl_->__add_weak();
+    shared_ptr<_Yp> __s = __r.lock();
+    *this = weak_ptr<_Tp>(__s);
 }
 
 template<class _Tp>
@@ -1749,11 +1749,12 @@ template<class _Yp, __enable_if_t<__compatible_with<_Yp, _Tp>::value, int> >
 inline
 weak_ptr<_Tp>::weak_ptr(weak_ptr<_Yp>&& __r)
          _NOEXCEPT
-    : __ptr_(__r.__ptr_),
-      __cntrl_(__r.__cntrl_)
+    : __ptr_(nullptr),
+      __cntrl_(nullptr)
 {
-    __r.__ptr_ = nullptr;
-    __r.__cntrl_ = nullptr;
+    shared_ptr<_Yp> __s = __r.lock();
+    *this = weak_ptr<_Tp>(__s);
+    __r.reset();
 }
 
 template<class _Tp>
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.const/pr40459.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.const/pr40459.pass.cpp
new file mode 100644
index 000000000000000..25141ad2de6c992
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.const/pr40459.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <memory>
+
+// weak_ptr
+
+// template<class Y> weak_ptr(const weak_ptr<Y>& r);
+// template<class Y> weak_ptr(weak_ptr<Y>&& r);
+//
+// Regression test for https://github.com/llvm/llvm-project/issues/40459
+// Verify that these constructors never attempt a derived-to-virtual-base
+// conversion on a dangling weak_ptr.
+
+#include <cassert>
+#include <cstring>
+#include <memory>
+#include <utility>
+
+#include "test_macros.h"
+
+struct A {
+  int i;
+  virtual ~A() {}
+};
+struct B : public virtual A {
+  int j;
+};
+struct Deleter {
+  void operator()(void*) const {
+    // do nothing
+  }
+};
+
+int main(int, char**) {
+#if TEST_STD_VER >= 11
+  alignas(B) char buffer[sizeof(B)];
+#else
+  std::aligned_storage<sizeof(B), std::alignment_of<B>::value>::type buffer;
+#endif
+  B *pb = ::new ((void*)&buffer) B();
+  std::shared_ptr<B> sp = std::shared_ptr<B>(pb, Deleter());
+  std::weak_ptr<B> wp = sp;
+  sp = nullptr;
+  assert(wp.expired());
+
+  // Overwrite the B object with junk.
+  std::memset(&buffer, '*', sizeof(buffer));
+
+  std::weak_ptr<A> wq = wp;
+  assert(wq.expired());
+  std::weak_ptr<A> wr = std::move(wp);
+  assert(wr.expired());
+
+  return 0;
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/67956


More information about the libcxx-commits mailing list