From e7aee30bbcbbaff25a2a377abaa3e4fc2b5d4aa6 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 15 Oct 2021 17:34:05 -0400 Subject: [PATCH] fix: use PyFrame_GetCode on Python 3.9+ --- include/pybind11/pybind11.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 285f3b18cb7..0d70c3bbab2 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2326,6 +2326,28 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty /* Don't call dispatch code if invoked from overridden function. Unfortunately this doesn't work on PyPy. */ #if !defined(PYPY_VERSION) + +#if PY_VERSION_HEX >= 0x03090000 + PyFrameObject *frame = PyThreadState_GetFrame(PyThreadState_Get()); + if (frame != nullptr) { + PyCodeObject *code = PyFrame_GetCode(frame); + if ((std::string) str(code->co_name) == name && code->co_argcount > 0) { + PyObject* locals = PyEval_GetLocals(); + if (locals != nullptr) { + PyObject *self_caller = dict_getitem( + locals, PyTuple_GET_ITEM(code->co_varnames, 0) + ); + if (self_caller == self.ptr()) { + Py_DECREF(code); + Py_DECREF(frame); + return function(); + } + } + } + Py_DECREF(code); + Py_DECREF(frame); + } +#else PyFrameObject *frame = PyThreadState_Get()->frame; if (frame != nullptr && (std::string) str(frame->f_code->co_name) == name && frame->f_code->co_argcount > 0) { @@ -2335,6 +2357,8 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty if (self_caller == self.ptr()) return function(); } +#endif + #else /* PyPy currently doesn't provide a detailed cpyext emulation of frame objects, so we have to emulate this using Python. This