From f09bd398cb758409a290b4f7b0632505404e6ea4 Mon Sep 17 00:00:00 2001 From: ykiko Date: Wed, 28 Aug 2024 11:27:10 +0800 Subject: [PATCH] fix memory leak in property and staticmethod. --- include/pybind11/internal/function.h | 16 ++----- include/pybind11/tests/operators.cpp | 69 ++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/include/pybind11/internal/function.h b/include/pybind11/internal/function.h index 934ea7a1..00dffa01 100644 --- a/include/pybind11/internal/function.h +++ b/include/pybind11/internal/function.h @@ -585,24 +585,14 @@ class cpp_function : public function { class property : public object { PKBIND_TYPE_IMPL(object, property, tp_property); - property(handle getter, handle setter = none()) : object() { - auto start = py_peek(0); - py_push(getter.ptr()); - py_push(setter.ptr()); - raise_call(type::of().index(), 2, start); - *this = object::from_ret(); - } + property(handle getter, handle setter = none()) : + object(type::of()(getter, setter)) {} }; class staticmethod : public object { PKBIND_TYPE_IMPL(object, staticmethod, tp_staticmethod); - staticmethod(handle method) : object() { - auto start = py_peek(0); - py_push(method.ptr()); - raise_call(type::of().index(), 1, start); - *this = object::from_ret(); - } + staticmethod(handle method) : object(type::of()(method)) {} }; namespace impl { diff --git a/include/pybind11/tests/operators.cpp b/include/pybind11/tests/operators.cpp index 378b0460..e8805697 100644 --- a/include/pybind11/tests/operators.cpp +++ b/include/pybind11/tests/operators.cpp @@ -1,5 +1,7 @@ +#include "pybind11/internal/builtins.h" #include "test.h" #include +#include namespace { @@ -8,19 +10,19 @@ struct Int { Int(int x) : x(x) {} -#define OPERATOR_IMPL(op) \ - template \ - friend int operator op (const LHS& lhs, const RHS& rhs) { \ - int l, r; \ - if constexpr(std::is_same_v) \ - l = lhs.x; \ - else \ - l = lhs; \ - if constexpr(std::is_same_v) \ - r = rhs.x; \ - else \ - r = rhs; \ - return l op r; \ +#define OPERATOR_IMPL(op) \ + template \ + friend int operator op (const LHS& lhs, const RHS& rhs) { \ + int l, r; \ + if constexpr(std::is_same_v) \ + l = lhs.x; \ + else \ + l = lhs; \ + if constexpr(std::is_same_v) \ + r = rhs.x; \ + else \ + r = rhs; \ + return l op r; \ } OPERATOR_IMPL(+) @@ -148,3 +150,44 @@ TEST_F(PYBIND11_TEST, logic_operators) { EXPECT_FALSE(a >= b); } +TEST_F(PYBIND11_TEST, item_operators) { + py::module_ m = py::module_::import("__main__"); + + py::class_>(m, "vector") + .def(py::init<>()) + .def("__getitem__", + [](std::vector& v, int i) { + return v[i]; + }) + .def("__setitem__", + [](std::vector& v, int i, int x) { + v[i] = x; + }) + .def("push_back", + [](std::vector& v, int x) { + v.push_back(x); + }) + .def("__str__", [](const std::vector& v) { + std::ostringstream os; + os << "["; + for(size_t i = 0; i < v.size(); i++) { + if(i > 0) os << ", "; + os << v[i]; + } + os << "]"; + return os.str(); + }); + + py::exec(R"( +v = vector() +v.push_back(1) +v.push_back(2) +v.push_back(3) +print(v) +assert v[0] == 1 +assert v[1] == 2 +assert v[2] == 3 +v[1] = 4 +assert v[1] == 4 +)"); +}