diff --git a/sip/siplib/sip.h b/sip/siplib/sip.h index ac180381..3fe6414f 100644 --- a/sip/siplib/sip.h +++ b/sip/siplib/sip.h @@ -54,8 +54,8 @@ extern "C" { /* * Define the SIP version number. */ -#define SIP_VERSION 0x040c04 -#define SIP_VERSION_STR "4.12.4" +#define SIP_VERSION 0x040c05 +#define SIP_VERSION_STR "4.12.5-snapshot-de6a700f5faa" /* @@ -68,6 +68,9 @@ extern "C" { * * History: * + * 8.2 Deprecated the old sip_api_is_py_method(). + * Added the new sip_api_is_py_method(). + * * 8.1 Revised the sipVariableDef structure. * sip_api_get_address() is now part of the public API. * @@ -175,7 +178,7 @@ extern "C" { * 0.0 Original version. */ #define SIP_API_MAJOR_NR 8 -#define SIP_API_MINOR_NR 1 +#define SIP_API_MINOR_NR 2 /* The name of the sip module. */ @@ -1415,7 +1418,7 @@ typedef struct _sipAPIDef { void (*api_bad_class)(const char *classname); void *(*api_get_cpp_ptr)(sipSimpleWrapper *w, const sipTypeDef *td); void *(*api_get_complex_cpp_ptr)(sipSimpleWrapper *w); - PyObject *(*api_is_py_method)(sip_gilstate_t *gil, char *pymc, + PyObject *(*api_is_py_method_old)(sip_gilstate_t *gil, char *pymc, sipSimpleWrapper *sipSelf, const char *cname, const char *mname); void (*api_call_hook)(const char *hookname); void (*api_start_thread)(void); @@ -1454,6 +1457,13 @@ typedef struct _sipAPIDef { * The following are part of the public API. */ void *(*api_get_address)(struct _sipSimpleWrapper *w); + + /* + * The following are not part of the public API. + */ + PyObject *(*api_is_py_method)(sip_gilstate_t *gil, char *pymc, + sipSimpleWrapper * const *sipSelfp, const char *cname, + const char *mname); } sipAPIDef; diff --git a/sip/siplib/siplib.c b/sip/siplib/siplib.c index 17e66dca..e134f269 100644 --- a/sip/siplib/siplib.c +++ b/sip/siplib/siplib.c @@ -203,6 +203,9 @@ static void sip_api_abstract_method(const char *classname, const char *method); static void sip_api_bad_class(const char *classname); static void *sip_api_get_complex_cpp_ptr(sipSimpleWrapper *sw); static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, + sipSimpleWrapper * const *sipSelfp, const char *cname, + const char *mname); +static PyObject *sip_api_is_py_method_old(sip_gilstate_t *gil, char *pymc, sipSimpleWrapper *sipSelf, const char *cname, const char *mname); static void sip_api_call_hook(const char *hookname); static void sip_api_raise_unknown_exception(void); @@ -339,7 +342,7 @@ static const sipAPIDef sip_api = { sip_api_bad_class, sip_api_get_cpp_ptr, sip_api_get_complex_cpp_ptr, - sip_api_is_py_method, + sip_api_is_py_method_old, sip_api_call_hook, sip_api_start_thread, sip_api_end_thread, @@ -366,7 +369,11 @@ static const sipAPIDef sip_api = { /* * The following are part of the public API. */ - sip_api_get_address + sip_api_get_address, + /* + * The following are not part of the public API. + */ + sip_api_is_py_method }; @@ -661,6 +668,8 @@ static int isNonlazyMethod(PyMethodDef *pmd); static int addMethod(PyObject *dict, PyMethodDef *pmd); static PyObject *create_property(sipVariableDef *vd); static PyObject *create_function(PyMethodDef *ml); +static PyObject *sip_exit(PyObject *obj, PyObject *ignore); +static void register_exit_notifier(void); /* @@ -857,6 +866,9 @@ PyMODINIT_FUNC SIP_MODULE_ENTRY(void) sipInterpreter = PyThreadState_Get()->interp; } + /* Make sure are notified when starting to exit. */ + register_exit_notifier(); + SIP_MODULE_RETURN(mod); } @@ -1545,7 +1557,10 @@ static void finalise(void) { sipExportedModuleDef *em; - /* Mark the Python API as unavailable. */ + /* + * Mark the Python API as unavailable. This should already have been done, + * but just in case... + */ sipInterpreter = NULL; /* Handle any delayed dtors. */ @@ -5203,7 +5218,7 @@ static void callPyDtor(sipSimpleWrapper *self) char pymc = 0; PyObject *meth; - meth = sip_api_is_py_method(&sipGILState, &pymc, self, NULL, "__dtor__"); + meth = sip_api_is_py_method(&sipGILState, &pymc, &self, NULL, "__dtor__"); if (meth != NULL) { @@ -7516,15 +7531,29 @@ static PyObject *getDictFromObject(PyObject *obj) } +/* + * Return a Python reimplementation corresponding to a C/C++ virtual function, + * if any. If one was found then the GIL is acquired. This is deprecated and + * only used by modules generated by an older version. + */ +static PyObject *sip_api_is_py_method_old(sip_gilstate_t *gil, char *pymc, + sipSimpleWrapper *sipSelf, const char *cname, const char *mname) +{ + return sip_api_is_py_method(gil, pymc, &sipSelf, cname, mname); +} + + /* * Return a Python reimplementation corresponding to a C/C++ virtual function, * if any. If one was found then the GIL is acquired. */ static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, - sipSimpleWrapper *sipSelf, const char *cname, const char *mname) + sipSimpleWrapper * const *sipSelfp, const char *cname, + const char *mname) { PyObject *mname_obj, *reimp, *mro, *cls; SIP_SSIZE_T i; + sipSimpleWrapper *sipSelf; /* * This is the most common case (where there is no Python reimplementation) @@ -7537,22 +7566,28 @@ static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, if (sipInterpreter == NULL) return NULL; +#ifdef WITH_THREAD + *gil = PyGILState_Ensure(); +#endif + /* * It's possible that the Python object has been deleted but the underlying * C++ instance is still working and trying to handle virtual functions. * Alternatively, an instance has started handling virtual functions before * its ctor has returned. In either case say there is no Python - * reimplementation. + * reimplementation. We do this with the GIL in case the object is in the + * process of being garbage collected. */ - if (sipSelf == NULL) + if ((sipSelf = *sipSelfp) == NULL) + { +#ifdef WITH_THREAD + PyGILState_Release(*gil); +#endif return NULL; + } /* Get any reimplementation. */ -#ifdef WITH_THREAD - *gil = PyGILState_Ensure(); -#endif - #if PY_MAJOR_VERSION >= 3 mname_obj = PyUnicode_FromString(mname); #else @@ -7575,6 +7610,8 @@ static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, */ if (add_all_lazy_attrs(((sipWrapperType *)Py_TYPE(sipSelf))->type) < 0) { + Py_DECREF(mname_obj); + #ifdef WITH_THREAD PyGILState_Release(*gil); #endif @@ -7617,7 +7654,7 @@ static PyObject *sip_api_is_py_method(sip_gilstate_t *gil, char *pymc, /* * Check any possible reimplementation is not the wrapped C++ method or - * a default special method implementation.. + * a default special method implementation. */ if (cls_dict != NULL && (cls_attr = PyDict_GetItem(cls_dict, mname_obj)) != NULL && Py_TYPE(cls_attr) != &sipMethodDescr_Type && Py_TYPE(cls_attr) != &PyWrapperDescr_Type) { @@ -10920,3 +10957,52 @@ static int check_encoded_string(PyObject *obj) return -1; } + + +/* + * This is called by the atexit module. + */ +static PyObject *sip_exit(PyObject *obj, PyObject *ignore) +{ + /* Disable all Python reimplementations of virtuals. */ + sipInterpreter = NULL; + + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * Register the exit notifier with the atexit module. + */ +static void register_exit_notifier(void) +{ + static PyMethodDef md = { + "_sip_exit", sip_exit, METH_NOARGS, NULL + }; + + PyObject *notifier, *atexit_module, *register_func, *res; + + if ((notifier = PyCFunction_New(&md, NULL)) == NULL) + return; + + if ((atexit_module = PyImport_ImportModule("atexit")) == NULL) + { + Py_DECREF(notifier); + return; + } + + if ((register_func = PyObject_GetAttrString(atexit_module, "register")) == NULL) + { + Py_DECREF(atexit_module); + Py_DECREF(notifier); + return; + } + + res = PyObject_CallFunctionObjArgs(register_func, notifier, NULL); + + Py_XDECREF(res); + Py_DECREF(register_func); + Py_DECREF(atexit_module); + Py_DECREF(notifier); +}