From 0fc54b04d6f47b74a35e4d13d5f62e459db20132 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Sat, 11 May 2019 16:48:08 +0200 Subject: Make the __signature__ attribute writable by default It turned out that the mock tool of the unittest module wants to write into a __signature__ attribute. We now allow this by implementing a writable attribute that memorizes any written value. When __del__ is used, the original value re-appears. We further added a check if a computed __signature__ attribute exists. Then we don't allow write access. This way, defined signatures are read-only, but a non-existent attribute stays writable. Change-Id: Ib70de723e3160787df04e075e5c540a4cb24d410 Fixes: PYSIDE-1004 Reviewed-by: Friedemann Kleint Reviewed-by: Cristian Maureira-Fredes --- sources/shiboken2/libshiboken/signature.cpp | 106 ++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 21 deletions(-) (limited to 'sources/shiboken2/libshiboken/signature.cpp') diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index 3defca7d2..c83f90d64 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -71,6 +71,7 @@ typedef struct safe_globals_struc { PyObject *helper_module; PyObject *arg_dict; PyObject *map_dict; + PyObject *value_dict; // for writing signatures // init part 2: run module PyObject *pyside_type_init_func; PyObject *create_signature_func; @@ -86,6 +87,7 @@ static PyObject *GetSignature_Function(PyObject *, const char *); static PyObject *GetSignature_TypeMod(PyObject *, const char *); static PyObject *GetSignature_Wrapper(PyObject *, const char *); static PyObject *get_signature(PyObject *self, PyObject *args); +static PyObject *get_signature_intern(PyObject *ob, const char *modifier); static PyObject *PySide_BuildSignatureProps(PyObject *class_mod); @@ -105,11 +107,36 @@ CreateSignature(PyObject *props, PyObject *key) const_cast("(OO)"), props, key); } +typedef PyObject *(*signaturefunc)(PyObject *, const char *); + +static PyObject * +_get_written_signature(signaturefunc sf, PyObject *ob, const char *modifier) +{ + /* + * Be a writable Attribute, but have a computed value. + * + * If a signature has not been written, call the signature function. + * If it has been written, return the written value. + * After __del__ was called, the function value re-appears. + * + * Note: This serves also for the new version that does not allow any + * assignment if we have a computed value. We only need to check if + * a computed value exists and then forbid writing. + * See pyside_set___signature + */ + PyObject *ret = PyDict_GetItem(pyside_globals->value_dict, ob); + if (ret == nullptr) { + return ob == nullptr ? nullptr : sf(ob, modifier); + } + Py_INCREF(ret); + return ret; +} + static PyObject * pyside_cf_get___signature__(PyObject *func, const char *modifier) { init_module_2(); - return GetSignature_Function(func, modifier); + return _get_written_signature(GetSignature_Function, func, modifier); } static PyObject * @@ -118,8 +145,8 @@ pyside_sm_get___signature__(PyObject *sm, const char *modifier) init_module_2(); Shiboken::AutoDecRef func(PyObject_GetAttrString(sm, "__func__")); if (Py_TYPE(func) == PepFunction_TypePtr) - Py_RETURN_NONE; - return GetSignature_Function(func, modifier); + return PyObject_GetAttrString(func, "__signature__"); + return _get_written_signature(GetSignature_Function, func, modifier); } static PyObject * @@ -270,14 +297,14 @@ static PyObject * pyside_wd_get___signature__(PyObject *ob, const char *modifier) { init_module_2(); - return GetSignature_Wrapper(ob, modifier); + return _get_written_signature(GetSignature_Wrapper, ob, modifier); } static PyObject * pyside_tp_get___signature__(PyObject *obtype_mod, const char *modifier) { init_module_2(); - return GetSignature_TypeMod(obtype_mod, modifier); + return _get_written_signature(GetSignature_TypeMod, obtype_mod, modifier); } // forward @@ -510,6 +537,12 @@ init_phase_1(void) if (p->arg_dict == nullptr || PyObject_SetAttrString(p->helper_module, "pyside_arg_dict", p->arg_dict) < 0) goto error; + + // build a dict for assigned signature values + p->value_dict = PyDict_New(); + if (p->value_dict == nullptr) + goto error; + return p; } error: @@ -682,33 +715,56 @@ pyside_wd_get___doc__(PyObject *wd) { return handle_doc(wd, old_wd_doc_descr); } +// the default setter for all objects +static int +pyside_set___signature__(PyObject *op, PyObject *value) +{ + // By this additional check, this function refuses write access. + if (get_signature_intern(op, nullptr)) { + PyErr_Format(PyExc_AttributeError, + "Attribute '__signature__' of '%.50s' object is not writable", + Py_TYPE(op)->tp_name); + return -1; + } + int ret = value == nullptr + ? PyDict_DelItem(pyside_globals->value_dict, op) + : PyDict_SetItem(pyside_globals->value_dict, op, value); + Py_XINCREF(value); + return ret; +} + static PyGetSetDef new_PyCFunction_getsets[] = { - {const_cast("__signature__"), (getter)pyside_cf_get___signature__}, {const_cast("__doc__"), (getter)pyside_cf_get___doc__}, + {const_cast("__signature__"), (getter)pyside_cf_get___signature__, + (setter)pyside_set___signature__}, {0} }; static PyGetSetDef new_PyStaticMethod_getsets[] = { - {const_cast("__signature__"), (getter)pyside_sm_get___signature__}, {const_cast("__doc__"), (getter)pyside_sm_get___doc__}, + {const_cast("__signature__"), (getter)pyside_sm_get___signature__, + (setter)pyside_set___signature__}, {0} }; static PyGetSetDef new_PyMethodDescr_getsets[] = { - {const_cast("__signature__"), (getter)pyside_md_get___signature__}, {const_cast("__doc__"), (getter)pyside_md_get___doc__}, + {const_cast("__signature__"), (getter)pyside_md_get___signature__, + (setter)pyside_set___signature__}, {0} }; static PyGetSetDef new_PyType_getsets[] = { - {const_cast("__signature__"), (getter)pyside_tp_get___signature__}, {const_cast("__doc__"), (getter)pyside_tp_get___doc__}, + {const_cast("__signature__"), (getter)pyside_tp_get___signature__, + (setter)pyside_set___signature__}, {0} }; static PyGetSetDef new_PyWrapperDescr_getsets[] = { - {const_cast("__signature__"), (getter)pyside_wd_get___signature__}, {const_cast("__doc__"), (getter)pyside_wd_get___doc__}, + {const_cast("__signature__"), (getter)pyside_wd_get___signature__, + (setter)pyside_set___signature__}, {0} }; @@ -723,18 +779,8 @@ static PyGetSetDef new_PyWrapperDescr_getsets[] = { // static PyObject * -get_signature(PyObject *self, PyObject *args) +get_signature_intern(PyObject *ob, const char *modifier) { - PyObject *ob; - const char *modifier = nullptr; - - init_module_1(); - - if (!PyArg_ParseTuple(args, "O|s", &ob, &modifier)) - return nullptr; - if (Py_TYPE(ob) == PepFunction_TypePtr) - Py_RETURN_NONE; - if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type)) return pyside_cf_get___signature__(ob, modifier); if (Py_TYPE(ob) == PepStaticMethod_TypePtr) @@ -745,6 +791,24 @@ get_signature(PyObject *self, PyObject *args) return pyside_tp_get___signature__(ob, modifier); if (Py_TYPE(ob) == &PyWrapperDescr_Type) return pyside_wd_get___signature__(ob, modifier); + return nullptr; +} + +static PyObject * +get_signature(PyObject *self, PyObject *args) +{ + PyObject *ob; + const char *modifier = nullptr; + + init_module_1(); + + if (!PyArg_ParseTuple(args, "O|s", &ob, &modifier)) + return nullptr; + if (Py_TYPE(ob) == PepFunction_TypePtr) + Py_RETURN_NONE; + PyObject *ret = get_signature_intern(ob, modifier); + if (ret != nullptr) + return ret; Py_RETURN_NONE; } -- cgit v1.2.3