From 72a2aec8481bd327136cba30772884729bb032a3 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 May 2025 00:07:16 -0400 Subject: [PATCH 1/2] fix: use original dict Signed-off-by: Henry Schreiner --- include/pybind11/detail/init.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h index ed95afe58c..4376315142 100644 --- a/include/pybind11/detail/init.h +++ b/include/pybind11/detail/init.h @@ -451,7 +451,10 @@ void setstate(value_and_holder &v_h, std::pair &&result, bool need_alias) // See PR #2972 for details. return; } - setattr((PyObject *) v_h.inst, "__dict__", d); + auto dict = getattr((PyObject *) v_h.inst, "__dict__"); + if (PyDict_Update(dict.ptr(), d.ptr()) < 0) { + throw error_already_set(); + } } /// Implementation for py::pickle(GetState, SetState) From 3626c268caa0888f0d2dc784ef7ff502b6212dfd Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 13 May 2025 11:43:41 -0400 Subject: [PATCH 2/2] refactor: handle unset dict just in case Signed-off-by: Henry Schreiner --- include/pybind11/detail/init.h | 12 +++++++++--- tests/test_pickling.cpp | 5 +---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h index 4376315142..92b20cb972 100644 --- a/include/pybind11/detail/init.h +++ b/include/pybind11/detail/init.h @@ -451,9 +451,15 @@ void setstate(value_and_holder &v_h, std::pair &&result, bool need_alias) // See PR #2972 for details. return; } - auto dict = getattr((PyObject *) v_h.inst, "__dict__"); - if (PyDict_Update(dict.ptr(), d.ptr()) < 0) { - throw error_already_set(); + // Our tests never run into an unset dict, but being careful here for now (see #5658) + auto dict = getattr((PyObject *) v_h.inst, "__dict__", none()); + if (dict.is_none()) { + setattr((PyObject *) v_h.inst, "__dict__", d); + } else { + // Keep the original object dict and just update it + if (PyDict_Update(dict.ptr(), d.ptr()) < 0) { + throw error_already_set(); + } } } diff --git a/tests/test_pickling.cpp b/tests/test_pickling.cpp index e154bc483c..6ba3d30eb9 100644 --- a/tests/test_pickling.cpp +++ b/tests/test_pickling.cpp @@ -35,10 +35,7 @@ void wrap(py::module m) { .def_readwrite("num", &SimpleBase::num) .def(py::pickle( [](const py::object &self) { - py::dict d; - if (py::hasattr(self, "__dict__")) { - d = self.attr("__dict__"); - } + py::dict d = py::getattr(self, "__dict__", py::dict()); return py::make_tuple(self.attr("num"), d); }, [](const py::tuple &t) {