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

Amirreza Ashouri via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 2 01:45:51 PDT 2023


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

>From d2eab55d99686be1a72cf511d2f4e66435d25120 Mon Sep 17 00:00:00 2001
From: Amirreza Ashouri <ar.ashouri999 at gmail.com>
Date: Sun, 1 Oct 2023 23:48:40 +0330
Subject: [PATCH] [libc++] Fix a segfault in weak_ptr(const weak_ptr<Y>&)

---
 libcxx/include/__memory/shared_ptr.h          | 17 +++---
 .../util.smartptr.weak.const/pr40459.pass.cpp | 61 +++++++++++++++++++
 2 files changed, 70 insertions(+), 8 deletions(-)
 create mode 100644 libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.weak/util.smartptr.weak.const/pr40459.pass.cpp

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..e94104fe8aa8ca5
--- /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;
+}



More information about the libcxx-commits mailing list