diff --git a/wxPython/contrib/ogl/ogl.cpp b/wxPython/contrib/ogl/ogl.cpp index 9de0ddb93f..3c74a41f61 100644 --- a/wxPython/contrib/ogl/ogl.cpp +++ b/wxPython/contrib/ogl/ogl.cpp @@ -172,7 +172,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { // already be a pointer to a Python object that we can use // in the OOR data. wxShapeEvtHandler* seh = (wxShapeEvtHandler*)source; - wxPyClientData* data = (wxPyClientData*)seh->GetClientObject(); + wxPyOORClientData* data = (wxPyOORClientData*)seh->GetClientObject(); if (data) { target = data->m_obj; Py_INCREF(target); @@ -181,7 +181,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { if (! target) { target = wxPyMake_wxObject2(source, FALSE); if (target != Py_None) - ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyClientData(target)); + ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target)); } return target; } diff --git a/wxPython/contrib/ogl/ogl.i b/wxPython/contrib/ogl/ogl.i index bdae01992f..dfa1a664a2 100644 --- a/wxPython/contrib/ogl/ogl.i +++ b/wxPython/contrib/ogl/ogl.i @@ -221,7 +221,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { // already be a pointer to a Python object that we can use // in the OOR data. wxShapeEvtHandler* seh = (wxShapeEvtHandler*)source; - wxPyClientData* data = (wxPyClientData*)seh->GetClientObject(); + wxPyOORClientData* data = (wxPyOORClientData*)seh->GetClientObject(); if (data) { target = data->m_obj; Py_INCREF(target); @@ -230,7 +230,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { if (! target) { target = wxPyMake_wxObject2(source, FALSE); if (target != Py_None) - ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyClientData(target)); + ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target)); } return target; } diff --git a/wxPython/contrib/ogl/oglbasic.cpp b/wxPython/contrib/ogl/oglbasic.cpp index 482538b0b2..c0bc910213 100644 --- a/wxPython/contrib/ogl/oglbasic.cpp +++ b/wxPython/contrib/ogl/oglbasic.cpp @@ -1249,7 +1249,7 @@ static PyObject *_wrap_wxPyShapeEvtHandler_Destroy(PyObject *self, PyObject *arg } static void wxPyShapeEvtHandler__setOORInfo(wxPyShapeEvtHandler *self,PyObject * _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } static PyObject *_wrap_wxPyShapeEvtHandler__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; diff --git a/wxPython/contrib/ogl/oglbasic.i b/wxPython/contrib/ogl/oglbasic.i index c1f6c83014..2338089016 100644 --- a/wxPython/contrib/ogl/oglbasic.i +++ b/wxPython/contrib/ogl/oglbasic.i @@ -99,7 +99,7 @@ public: %addmethods { void Destroy() { delete self; } } %addmethods { void _setOORInfo(PyObject* _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } } diff --git a/wxPython/src/_extras.py b/wxPython/src/_extras.py index 708d1fd586..866ab98cf7 100644 --- a/wxPython/src/_extras.py +++ b/wxPython/src/_extras.py @@ -647,6 +647,26 @@ def wxPyTypeCast(obj, typeStr): return theObj +#---------------------------------------------------------------------------- + + +class _wxPyDeadObject: + """ + Instances of wx objects that are OOR capable will have their __class__ + changed to this class when the C++ object is deleted. This should help + prevent crashes due to referencing a bogus C++ pointer. + """ + def __repr__( self ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + return 'wxPython wrapper for deleted %s object!!! Programming logic error' % self._name + + def __getattr__( self, *args ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + raise ValueError, 'Attempt to access attribute of a deleted %s object' % self._name + + #---------------------------------------------------------------------- #---------------------------------------------------------------------- @@ -763,10 +783,10 @@ class wxPyWidgetTester(wxApp): self.frame.Show(true) #---------------------------------------------------------------------------- -# DO NOT hold any other references to this object. This is how we know when -# to cleanup system resources that wxWin is holding. When this module is -# unloaded, the refcount on __cleanMeUp goes to zero and it calls the -# wxApp_CleanUp function. +# DO NOT hold any other references to this object. This is how we +# know when to cleanup system resources that wxWin is holding. When +# the sys module is unloaded, the refcount on sys.__wxPythonCleanup +# goes to zero and it calls the wxApp_CleanUp function. class __wxPyCleanup: def __init__(self): diff --git a/wxPython/src/export.h b/wxPython/src/export.h index c0b9c25a67..a38a1c7a67 100644 --- a/wxPython/src/export.h +++ b/wxPython/src/export.h @@ -74,6 +74,9 @@ static void wxPyCoreAPI_IMPORT() { #define wxArrayString2PyList_helper(a) (wxPyCoreAPIPtr->p_wxArrayString2PyList_helper(a)) #define wxArrayInt2PyList_helper(a) (wxPyCoreAPIPtr->p_wxArrayInt2PyList_helper(a)) +#define wxPyClientData_dtor(a) (wxPyCoreAPIPtr->p_wxPyClientData_dtor(a)) +#define wxPyUserData_dtor(a) (wxPyCoreAPIPtr->p_wxPyUserData_dtor(a)) +#define wxPyOORClientData_dtor(a) (wxPyCoreAPIPtr->p_wxPyOORClientData_dtor(a)) // This one is special. It's the first function called in SWIG generated // modules, so we'll use it to also import the API. diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index aa48fa7128..c3c52d2a6e 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -295,6 +295,7 @@ void __wxCleanup() { static PyObject* wxPython_dict = NULL; static PyObject* wxPyPtrTypeMap = NULL; + PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) { @@ -334,6 +335,52 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) return Py_None; } +//--------------------------------------------------------------------------- + +void wxPyClientData_dtor(wxPyClientData* self) { + wxPyBeginBlockThreads(); + Py_DECREF(self->m_obj); + wxPyEndBlockThreads(); +} + +void wxPyUserData_dtor(wxPyUserData* self) { + wxPyBeginBlockThreads(); + Py_DECREF(self->m_obj); + wxPyEndBlockThreads(); +} + + +// This is called when an OOR controled object is being destroyed. Although +// the C++ object is going away there is no way to force the Python object +// (and all references to it) to die too. This causes problems (crashes) in +// wxPython when a python shadow object attempts to call a C++ method using +// the now bogus pointer... So to try and prevent this we'll do a little black +// magic and change the class of the python instance to a class that will +// raise an exception for any attempt to call methods with it. See +// _wxPyDeadObject in _extras.py for the implementation of this class. +void wxPyOORClientData_dtor(wxPyOORClientData* self) { + + static PyObject* deadObjectClass = NULL; + + wxPyBeginBlockThreads(); + if (deadObjectClass == NULL) { + deadObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyDeadObject"); + wxASSERT_MSG(deadObjectClass != NULL, wxT("Can't get _wxPyDeadObject class!")); + Py_INCREF(deadObjectClass); + } + + // Clear the instance's dictionary, put the name of the old class into the + // instance, and then reset the class to be the dead class. + if (self->m_obj->ob_refcnt > 1) { // but only if there is more than one reference + wxASSERT_MSG(PyInstance_Check(self->m_obj), wxT("m_obj not an instance!?!?!")); + PyInstanceObject* inst = (PyInstanceObject*)self->m_obj; + PyDict_Clear(inst->in_dict); + PyDict_SetItemString(inst->in_dict, "_name", inst->in_class->cl_name); + inst->in_class = (PyClassObject*)deadObjectClass; + Py_INCREF(deadObjectClass); + } + wxPyEndBlockThreads(); +} //--------------------------------------------------------------------------- // Stuff used by OOR to find the right wxPython class type to return and to @@ -344,6 +391,7 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args) // is not the same as the shadow class name, for example wxPyTreeCtrl // vs. wxTreeCtrl. It needs to be referenced in Python as well as from C++, // so we'll just make it a Python dictionary in the wx module's namespace. +// (See __wxSetDictionary) void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) { if (! wxPyPtrTypeMap) wxPyPtrTypeMap = PyDict_New(); @@ -379,7 +427,7 @@ PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) { if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) { isEvtHandler = TRUE; wxEvtHandler* eh = (wxEvtHandler*)source; - wxPyClientData* data = (wxPyClientData*)eh->GetClientObject(); + wxPyOORClientData* data = (wxPyOORClientData*)eh->GetClientObject(); if (data) { target = data->m_obj; Py_INCREF(target); @@ -400,9 +448,9 @@ PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) { if (info) { target = wxPyConstructObject(source, name, klass, FALSE); if (target && isEvtHandler) - ((wxEvtHandler*)source)->SetClientObject(new wxPyClientData(target)); + ((wxEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target)); } else { - wxString msg("wxPython class not found for "); + wxString msg(wxT("wxPython class not found for ")); msg += source->GetClassInfo()->GetClassName(); PyErr_SetString(PyExc_NameError, msg.mbc_str()); target = NULL; @@ -423,7 +471,7 @@ PyObject* wxPyMake_wxSizer(wxSizer* source) { // already be a pointer to a Python object that we can use // in the OOR data. wxSizer* sz = (wxSizer*)source; - wxPyClientData* data = (wxPyClientData*)sz->GetClientObject(); + wxPyOORClientData* data = (wxPyOORClientData*)sz->GetClientObject(); if (data) { target = data->m_obj; Py_INCREF(target); @@ -432,7 +480,7 @@ PyObject* wxPyMake_wxSizer(wxSizer* source) { if (! target) { target = wxPyMake_wxObject(source, FALSE); if (target != Py_None) - ((wxSizer*)source)->SetClientObject(new wxPyClientData(target)); + ((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target)); } return target; } diff --git a/wxPython/src/helpers.h b/wxPython/src/helpers.h index 50ba510883..4ec75ec534 100644 --- a/wxPython/src/helpers.h +++ b/wxPython/src/helpers.h @@ -101,6 +101,9 @@ bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj); bool wxRect_helper(PyObject* source, wxRect** obj); bool wxColour_helper(PyObject* source, wxColour** obj); +//---------------------------------------------------------------------- +// Other helpful stuff + #if PYTHON_API_VERSION < 1009 #define PySequence_Fast_GET_ITEM(o, i) \ (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i)) @@ -113,9 +116,9 @@ bool _4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4); PyObject* wxArrayString2PyList_helper(const wxArrayString& arr); PyObject* wxArrayInt2PyList_helper(const wxArrayInt& arr); - -#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; } -#define DECLARE_DEF_STRING(name) static wxString wxPy##name(wx##name) +#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; } +#define DECLARE_DEF_STRING(name) static const wxString wxPy##name(wx##name) +#define DECLARE_DEF_STRING2(name,val) static const wxString wxPy##name(val) //---------------------------------------------------------------------- @@ -201,6 +204,18 @@ public: }; + +//---------------------------------------------------------------------- +// Forward decalre a few things used in the exported API +class wxPyClientData; +class wxPyUserData; +class wxPyOORClientData; + +void wxPyClientData_dtor(wxPyClientData* self); +void wxPyUserData_dtor(wxPyUserData* self); +void wxPyOORClientData_dtor(wxPyOORClientData* self); + + //--------------------------------------------------------------------------- // Export a C API in a struct. Other modules will be able to load this from // the wxc module and will then have safe access to these functions, even if @@ -256,12 +271,70 @@ struct wxPyCoreAPI { void (*p_wxPyPtrTypeMap_Add)(const char* commonName, const char* ptrName); PyObject* (*p_wxArrayString2PyList_helper)(const wxArrayString& arr); PyObject* (*p_wxArrayInt2PyList_helper)(const wxArrayInt& arr); + + void (*p_wxPyClientData_dtor)(wxPyClientData*); + void (*p_wxPyUserData_dtor)(wxPyUserData*); + void (*p_wxPyOORClientData_dtor)(wxPyOORClientData*); }; #ifdef wxPyUSE_EXPORT -static wxPyCoreAPI* wxPyCoreAPIPtr = NULL; // Each module needs one, but may not use it. +static wxPyCoreAPI* wxPyCoreAPIPtr = NULL; // Each module needs one, but doesn't have to use it. #endif + +//--------------------------------------------------------------------------- + + +class wxPyUserData : public wxObject { +public: + wxPyUserData(PyObject* obj) { + m_obj = obj; + Py_INCREF(m_obj); + } + + ~wxPyUserData() { +#ifdef wxPyUSE_EXPORT + wxPyCoreAPIPtr->p_wxPyUserData_dtor(this); +#else + wxPyUserData_dtor(this); +#endif + } + PyObject* m_obj; +}; + + +class wxPyClientData : public wxClientData { +public: + wxPyClientData(PyObject* obj) { + m_obj = obj; + Py_INCREF(m_obj); + } + + ~wxPyClientData() { +#ifdef wxPyUSE_EXPORT + wxPyCoreAPIPtr->p_wxPyClientData_dtor(this); +#else + wxPyClientData_dtor(this); +#endif + } + PyObject* m_obj; +}; + + +class wxPyOORClientData : public wxPyClientData { +public: + wxPyOORClientData(PyObject* obj) + : wxPyClientData(obj) {} + + ~wxPyOORClientData() { +#ifdef wxPyUSE_EXPORT + wxPyCoreAPIPtr->p_wxPyOORClientData_dtor(this); +#else + wxPyOORClientData_dtor(this); +#endif + } +}; + //--------------------------------------------------------------------------- // This class holds an instance of a Python Shadow Class object and assists // with looking up and invoking Python callback methods from C++ virtual @@ -312,53 +385,6 @@ void wxPyCBH_delete(wxPyCallbackHelper* cbh); -//---------------------------------------------------------------------- - -class wxPyUserData : public wxObject { -public: - wxPyUserData(PyObject* obj) { - m_obj = obj; - Py_INCREF(m_obj); - } - - ~wxPyUserData() { -#ifdef wxPyUSE_EXPORT - wxPyCoreAPIPtr->p_wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyCoreAPIPtr->p_wxPyEndBlockThreads(); -#else - wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyEndBlockThreads(); -#endif - } - PyObject* m_obj; -}; - - - -class wxPyClientData : public wxClientData { -public: - wxPyClientData(PyObject* obj) { - m_obj = obj; - Py_INCREF(m_obj); - } - - ~wxPyClientData() { -#ifdef wxPyUSE_EXPORT - wxPyCoreAPIPtr->p_wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyCoreAPIPtr->p_wxPyEndBlockThreads(); -#else - wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyEndBlockThreads(); -#endif - } - PyObject* m_obj; -}; - - //--------------------------------------------------------------------------- // These macros are used to implement the virtual methods that should diff --git a/wxPython/src/msw/gdi.py b/wxPython/src/msw/gdi.py index eda13bc5ec..9ab2cec48f 100644 --- a/wxPython/src/msw/gdi.py +++ b/wxPython/src/msw/gdi.py @@ -866,14 +866,14 @@ class wxBufferedDC(wxBufferedDCPtr): def __init__(self,*_args,**_kwargs): self.this = apply(gdic.new_wxBufferedDC,_args,_kwargs) self.thisown = 1 - self._dc = _args[0] # save a ref so it won't be deleted before self + self._dc = _args[0] # save a ref so the other dc won't be deleted before self def wxBufferedDCInternalBuffer(*_args,**_kwargs): val = wxBufferedDCPtr(apply(gdic.new_wxBufferedDCInternalBuffer,_args,_kwargs)) val.thisown = 1 - val._dc = _args[0] # save a ref so it won't be deleted before self + val._dc = _args[0] # save a ref so the other dc won't be deleted before self return val diff --git a/wxPython/src/msw/sizers.cpp b/wxPython/src/msw/sizers.cpp index 5bddf40caf..bc740b04cf 100644 --- a/wxPython/src/msw/sizers.cpp +++ b/wxPython/src/msw/sizers.cpp @@ -860,7 +860,7 @@ static void *SwigwxSizerTowxObject(void *ptr) { } static void wxSizer__setOORInfo(wxSizer *self,PyObject * _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } static PyObject *_wrap_wxSizer__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; diff --git a/wxPython/src/msw/utils.cpp b/wxPython/src/msw/utils.cpp index 4475235a09..657cefed9c 100644 --- a/wxPython/src/msw/utils.cpp +++ b/wxPython/src/msw/utils.cpp @@ -55,14 +55,13 @@ extern PyObject *SWIG_newvarlink(void); #define SWIG_name "utilsc" -#include "export.h" +#include "helpers.h" #include #include #include // Put some wx default wxChar* values into wxStrings. - static const wxChar* wxDateFormatStr = wxT("sashWindow"); - DECLARE_DEF_STRING(DateFormatStr); + DECLARE_DEF_STRING2(DateFormatStr, wxT("sashWindow")); static const wxString wxPyEmptyString(wxT("")); diff --git a/wxPython/src/msw/windows.cpp b/wxPython/src/msw/windows.cpp index 228779aa2b..93f30a99af 100644 --- a/wxPython/src/msw/windows.cpp +++ b/wxPython/src/msw/windows.cpp @@ -548,7 +548,7 @@ static PyObject *_wrap_wxEvtHandler_Disconnect(PyObject *self, PyObject *args, P } static void wxEvtHandler__setOORInfo(wxEvtHandler *self,PyObject * _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } static PyObject *_wrap_wxEvtHandler__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; diff --git a/wxPython/src/msw/wx.cpp b/wxPython/src/msw/wx.cpp index fe8e6ac8c3..7d73f40df8 100644 --- a/wxPython/src/msw/wx.cpp +++ b/wxPython/src/msw/wx.cpp @@ -677,7 +677,11 @@ static wxPyCoreAPI API = { wxPyMake_wxSizer, wxPyPtrTypeMap_Add, wxArrayString2PyList_helper, - wxArrayInt2PyList_helper + wxArrayInt2PyList_helper, + + wxPyClientData_dtor, + wxPyUserData_dtor, + wxPyOORClientData_dtor }; diff --git a/wxPython/src/msw/wx.py b/wxPython/src/msw/wx.py index 2cc382ee35..35e1ba43d2 100644 --- a/wxPython/src/msw/wx.py +++ b/wxPython/src/msw/wx.py @@ -1554,6 +1554,26 @@ def wxPyTypeCast(obj, typeStr): return theObj +#---------------------------------------------------------------------------- + + +class _wxPyDeadObject: + """ + Instances of wx objects that are OOR capable will have their __class__ + changed to this class when the C++ object is deleted. This should help + prevent crashes due to referencing a bogus C++ pointer. + """ + def __repr__( self ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + return 'wxPython wrapper for deleted %s object!!! Programming logic error' % self._name + + def __getattr__( self, *args ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + raise ValueError, 'Attempt to access attribute of a deleted %s object' % self._name + + #---------------------------------------------------------------------- #---------------------------------------------------------------------- @@ -1670,10 +1690,10 @@ class wxPyWidgetTester(wxApp): self.frame.Show(true) #---------------------------------------------------------------------------- -# DO NOT hold any other references to this object. This is how we know when -# to cleanup system resources that wxWin is holding. When this module is -# unloaded, the refcount on __cleanMeUp goes to zero and it calls the -# wxApp_CleanUp function. +# DO NOT hold any other references to this object. This is how we +# know when to cleanup system resources that wxWin is holding. When +# the sys module is unloaded, the refcount on sys.__wxPythonCleanup +# goes to zero and it calls the wxApp_CleanUp function. class __wxPyCleanup: def __init__(self): diff --git a/wxPython/src/sizers.i b/wxPython/src/sizers.i index a43993df98..1e65076ff9 100644 --- a/wxPython/src/sizers.i +++ b/wxPython/src/sizers.i @@ -97,7 +97,7 @@ public: %addmethods { void _setOORInfo(PyObject* _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } } diff --git a/wxPython/src/utils.i b/wxPython/src/utils.i index ada7c8ad11..24a33a10ef 100644 --- a/wxPython/src/utils.i +++ b/wxPython/src/utils.i @@ -14,7 +14,7 @@ %module utils %{ -#include "export.h" +#include "helpers.h" #include #include #include @@ -23,8 +23,7 @@ //--------------------------------------------------------------------------- %{ // Put some wx default wxChar* values into wxStrings. - static const wxChar* wxDateFormatStr = wxT("sashWindow"); - DECLARE_DEF_STRING(DateFormatStr); + DECLARE_DEF_STRING2(DateFormatStr, wxT("sashWindow")); static const wxString wxPyEmptyString(wxT("")); %} diff --git a/wxPython/src/windows.i b/wxPython/src/windows.i index a79cea8664..10778765a6 100644 --- a/wxPython/src/windows.i +++ b/wxPython/src/windows.i @@ -87,7 +87,7 @@ public: %addmethods { void _setOORInfo(PyObject* _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } } }; diff --git a/wxPython/src/wx.i b/wxPython/src/wx.i index f51a623b6d..351c6e4bb1 100644 --- a/wxPython/src/wx.i +++ b/wxPython/src/wx.i @@ -202,7 +202,11 @@ static wxPyCoreAPI API = { wxPyMake_wxSizer, wxPyPtrTypeMap_Add, wxArrayString2PyList_helper, - wxArrayInt2PyList_helper + wxArrayInt2PyList_helper, + + wxPyClientData_dtor, + wxPyUserData_dtor, + wxPyOORClientData_dtor };