From 76e77701344dee0bd9be831ea117901026026c67 Mon Sep 17 00:00:00 2001
From: "Ralf W. Grosse-Kunstleve" <rwgk@google.com>
Date: Mon, 23 Nov 2020 10:34:11 -0800
Subject: [PATCH] TRIGGER_SEGSEV macro, annotations for GET_STACK (vptr::get),
 GET_INT_STACK (pointee)

---
 include/pybind11/cast.h          |  4 ++--
 include/pybind11/pybind11.h      | 18 ++++++++++--------
 include/pybind11/vptr_holder.h   | 13 +++++++++----
 tests/test_unique_ptr_member.cpp |  1 +
 tests/work.py                    | 12 ++++++++++++
 5 files changed, 34 insertions(+), 14 deletions(-)
 create mode 100644 tests/work.py

diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 72b3a87fd..6effa1bc0 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -2037,7 +2037,7 @@ public:
 
     template <typename Return, typename Guard, typename Func>
     enable_if_t<!std::is_void<Return>::value, Return> call(Func &&f) && {
-        return std::move(*this).template call_impl<Return>(std::forward<Func>(f), indices{}, Guard{});
+        return std::move(*this).template call_impl<Return>(std::forward<Func>(f), indices{}, Guard{});  // GET_INT_STACK -3
     }
 
     template <typename Return, typename Guard, typename Func>
@@ -2065,7 +2065,7 @@ private:
 
     template <typename Return, typename Func, size_t... Is, typename Guard>
     Return call_impl(Func &&f, index_sequence<Is...>, Guard &&) && {
-        return std::forward<Func>(f)(cast_op<Args>(std::move(std::get<Is>(argcasters)))...);
+        return std::forward<Func>(f)(cast_op<Args>(std::move(std::get<Is>(argcasters)))...);  // GET_INT_STACK -2
     }
 
     std::tuple<make_caster<Args>...> argcasters;
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index 08c51c6f9..23599f214 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -56,6 +56,8 @@
 #  include <cxxabi.h>
 #endif
 
+#define TRIGGER_SEGSEV { unsigned long *bad = nullptr; *bad = -1; }
+
 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 
 /// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
@@ -97,7 +99,7 @@ public:
     /// Construct a cpp_function from a class method (const, no ref-qualifier)
     template <typename Return, typename Class, typename... Arg, typename... Extra>
     cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) {
-        initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
+        initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },  // GET_INT_STACK -1
                    (Return (*)(const Class *, Arg ...)) nullptr, extra...);
     }
 
@@ -167,7 +169,7 @@ protected:
                       "The number of argument annotations does not match the number of function arguments");
 
         /* Dispatch code which converts function arguments and performs the actual function call */
-        rec->impl = [](function_call &call) -> handle {
+        rec->impl = [](function_call &call) -> handle {  // GET_INT_STACK -5
             cast_in args_converter;
 
             /* Try to cast the function arguments into the C++ domain */
@@ -190,7 +192,7 @@ protected:
 
             /* Perform the function call */
             handle result = cast_out::cast(
-                std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent);
+                std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent);  // GET_INT_STACK -4
 
             /* Invoke call policy post-call hook */
             process_attributes<Extra...>::postcall(call, result);
@@ -552,7 +554,7 @@ protected:
         handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr,
                result = PYBIND11_TRY_NEXT_OVERLOAD;
 
-        auto self_value_and_holder = value_and_holder();
+        auto self_value_and_holder = value_and_holder(); // cast.h
         if (overloads->is_constructor) {
             if (!PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) {
                 PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid `self` argument");
@@ -764,7 +766,7 @@ protected:
                 // 6. Call the function.
                 try {
                     loader_life_support guard{};
-                    result = func.impl(call);
+                    result = func.impl(call);  // GET_INT_STACK -6
                 } catch (reference_cast_error &) {
                     result = PYBIND11_TRY_NEXT_OVERLOAD;
                 }
@@ -930,7 +932,7 @@ protected:
         } else {
             if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) {
                 auto *pi = reinterpret_cast<instance *>(parent.ptr());
-                self_value_and_holder.type->init_instance(pi, nullptr);
+                self_value_and_holder.type->init_instance(pi, nullptr);  // GET_STACK -4
             }
             return result.ptr();
         }
@@ -1536,7 +1538,7 @@ private:
             init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
             v_h.set_holder_constructed();
         } else if (inst->owned || detail::always_construct_holder<holder_type>::value) {
-            new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
+            new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());  // GET_STACK -2
             v_h.set_holder_constructed();
         }
     }
@@ -1551,7 +1553,7 @@ private:
             register_instance(inst, v_h.value_ptr(), v_h.type);
             v_h.set_instance_registered();
         }
-        init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());
+        init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());  // GET_STACK -3
     }
 
     /// Deallocates an instance; via holder, if constructed; otherwise via operator delete.
diff --git a/include/pybind11/vptr_holder.h b/include/pybind11/vptr_holder.h
index 39ef5206d..1de37adc8 100644
--- a/include/pybind11/vptr_holder.h
+++ b/include/pybind11/vptr_holder.h
@@ -2,6 +2,7 @@
 
 #include <pybind11/pybind11.h>
 
+#include <iostream>
 #include <memory>
 #include <variant>
 
@@ -11,9 +12,12 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 // To enable passing of unique_ptr as in pure C++.
 template <typename T> class vptr {
   public:
-    explicit vptr(T *ptr = nullptr) : vptr_{std::unique_ptr<T>(ptr)} {}
-    explicit vptr(std::unique_ptr<T> u) : vptr_{std::move(u)} {}
-    explicit vptr(std::shared_ptr<T> s) : vptr_{s} {}
+    explicit vptr(T *ptr = nullptr) : vptr_{std::unique_ptr<T>(ptr)} {
+        std::cout << std::endl << "explicit vptr(T *ptr = nullptr)" << std::endl;
+        //TRIGGER_SEGSEV
+    }
+    explicit vptr(std::unique_ptr<T> u) : vptr_{std::move(u)} { std::cout << std::endl << "explicit vptr(std::unique_ptr<T> u)" << std::endl; }
+    explicit vptr(std::shared_ptr<T> s) : vptr_{s} { std::cout << std::endl << "explicit vptr(std::shared_ptr<T> s)" << std::endl; }
 
     int ownership_type() const {
         if (std::get_if<0>(&vptr_)) {
@@ -26,6 +30,7 @@ template <typename T> class vptr {
     }
 
     T *get() {
+        std::cout << std::endl << "vptr::get" << std::endl;
         auto u = std::get_if<0>(&vptr_);
         if (u) {
             return u->get();
@@ -64,7 +69,7 @@ template <typename T> class vptr {
 };
 
 template <typename T> class vptr_holder : public vptr<T> {
-    using vptr<T>::vptr;
+    using vptr<T>::vptr;  // GET_STACK -1
 };
 
 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/tests/test_unique_ptr_member.cpp b/tests/test_unique_ptr_member.cpp
index 38a99a679..ebe5e09ee 100644
--- a/tests/test_unique_ptr_member.cpp
+++ b/tests/test_unique_ptr_member.cpp
@@ -16,6 +16,7 @@ class pointee { // NOT copyable.
 
     int get_int() const {
         to_cout("pointee::get_int()");
+        //TRIGGER_SEGSEV
         return 213;
     }
 
diff --git a/tests/work.py b/tests/work.py
new file mode 100644
index 000000000..11dd213b4
--- /dev/null
+++ b/tests/work.py
@@ -0,0 +1,12 @@
+from pybind11_tests import unique_ptr_member as m
+
+
+def test_pointee_and_ptr_owner():
+    m.to_cout("")
+    obj = m.pointee()
+    assert obj.get_int() == 213
+    del obj
+    print("DONE.", flush=True)
+
+
+test_pointee_and_ptr_owner()