From bd193696b8d539504c8cee0cc14cebc97adb2e8a Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 15 Aug 2025 12:15:55 +0100 Subject: [PATCH] Prevent infinite recursion if python class doesn't override all methods * We shouldn't require 'pure virtual' functions in CaptureViewer implementations in python, so detect when the derived class methods point to the base class pass-throughs, and skip them in that case. --- qrenderdoc/Code/pyrenderdoc/qrenderdoc.i | 57 ++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i index fc3e1ea7a..54fed1af6 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i @@ -73,6 +73,11 @@ TEMPLATE_FIXEDARRAY_DECLARE(rdcfixedarray); // create a wrapper for passing python ICaptureViewer interface implementations to C++ %{ + extern "C" SWIGINTERN PyObject *_wrap_CaptureViewer_OnCaptureLoaded(PyObject *self, PyObject *args); + extern "C" SWIGINTERN PyObject *_wrap_CaptureViewer_OnCaptureClosed(PyObject *self, PyObject *args); + extern "C" SWIGINTERN PyObject *_wrap_CaptureViewer_OnSelectedEventChanged(PyObject *self, PyObject *args); + extern "C" SWIGINTERN PyObject *_wrap_CaptureViewer_OnEventChanged(PyObject *self, PyObject *args); + struct PythonCaptureViewer : public ICaptureViewer { PythonCaptureViewer(PyObject *s) : self(s) @@ -85,26 +90,62 @@ TEMPLATE_FIXEDARRAY_DECLARE(rdcfixedarray); { meth = PyObject_GetAttrString(self, "OnCaptureLoaded"); - m_OnCaptureLoaded = ConvertFunc>("ICaptureViewer::OnCaptureLoaded", meth, ex); - Py_XDECREF(meth); + if(PyCFunction_Check(meth) && PyCFunction_GetFunction(meth) == &_wrap_CaptureViewer_OnCaptureLoaded) + { + Py_XDECREF(meth); + meth = NULL; + } + + if(meth) + { + m_OnCaptureLoaded = ConvertFunc>("ICaptureViewer::OnCaptureLoaded", meth, ex); + Py_XDECREF(meth); + } } { meth = PyObject_GetAttrString(self, "OnCaptureClosed"); - m_OnCaptureClosed = ConvertFunc>("ICaptureViewer::OnCaptureClosed", meth, ex); - Py_XDECREF(meth); + if(PyCFunction_Check(meth) && PyCFunction_GetFunction(meth) == &_wrap_CaptureViewer_OnCaptureClosed) + { + Py_XDECREF(meth); + meth = NULL; + } + + if(meth) + { + m_OnCaptureClosed = ConvertFunc>("ICaptureViewer::OnCaptureClosed", meth, ex); + Py_XDECREF(meth); + } } { meth = PyObject_GetAttrString(self, "OnSelectedEventChanged"); - m_OnSelectedEventChanged = ConvertFunc>("ICaptureViewer::OnSelectedEventChanged", meth, ex); - Py_XDECREF(meth); + if(PyCFunction_Check(meth) && PyCFunction_GetFunction(meth) == &_wrap_CaptureViewer_OnSelectedEventChanged) + { + Py_XDECREF(meth); + meth = NULL; + } + + if(meth) + { + m_OnSelectedEventChanged = ConvertFunc>("ICaptureViewer::OnSelectedEventChanged", meth, ex); + Py_XDECREF(meth); + } } { meth = PyObject_GetAttrString(self, "OnEventChanged"); - m_OnEventChanged = ConvertFunc>("ICaptureViewer::OnEventChanged", meth, ex); - Py_XDECREF(meth); + if(PyCFunction_Check(meth) && PyCFunction_GetFunction(meth) == &_wrap_CaptureViewer_OnEventChanged) + { + Py_XDECREF(meth); + meth = NULL; + } + + if(meth) + { + m_OnEventChanged = ConvertFunc>("ICaptureViewer::OnEventChanged", meth, ex); + Py_XDECREF(meth); + } } }