diff options
author | Christian Tismer <tismer@stackless.com> | 2019-04-12 10:58:02 +0200 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2019-04-16 08:07:38 +0000 |
commit | c9f522f082485186dcd8be80186e3c11b55f2b77 (patch) | |
tree | 24a95c682a4ba6ce712c229228c7b74e733b67f8 /sources/shiboken2/libshiboken/signature.cpp | |
parent | e0aa898c068006a7b6aef4cdb0528f2d0b8e0a94 (diff) |
Ensure that signature strings never overflow again
The signature module used to use large strings with the signatures
of all functions in a class. This can lead to an overflow in MSVC,
because the maximum string length funnily still is 32K unicode
characters.
This patch solves that by using a single string per function.
Instead of a huge string, a list of strings is passed to each class.
To prevent any runtime increase, the string list creation is deferred
until the actual usage. At initialization time only a ssize_t holding
the structure address is passed.
As a result, the signature module should be even slightly faster.
Task-number: PYSIDE-955
Change-Id: I99faf942a3cca03456928b8aec5e8a4b9924b8b2
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'sources/shiboken2/libshiboken/signature.cpp')
-rw-r--r-- | sources/shiboken2/libshiboken/signature.cpp | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index 8d580b487..3defca7d2 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -61,6 +61,7 @@ extern "C" #define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3) #define PYTHON_EXPOSES_METHODDESCR (PYTHON_IS_PYTHON3) #define PYTHON_NO_TYPE_IN_FUNCTIONS (!PYTHON_IS_PYTHON3 || Py_LIMITED_API) +#define PYTHON_HAS_INT_AND_LONG (!PYTHON_IS_PYTHON3) // These constants are still in use: #define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000) @@ -326,7 +327,7 @@ TypeKey_to_PropsDict(PyObject *type_key, PyObject *obtype) dict = empty_dict; } if (!PyDict_Check(dict)) - dict = PySide_BuildSignatureProps(obtype); + dict = PySide_BuildSignatureProps(type_key); return dict; } @@ -821,16 +822,23 @@ init_module_1(void) } static int -PySide_BuildSignatureArgs(PyObject *obtype_mod, const char *signatures) +PySide_BuildSignatureArgs(PyObject *obtype_mod, const char *signatures[]) { init_module_1(); Shiboken::AutoDecRef type_key(GetTypeKey(obtype_mod)); - Shiboken::AutoDecRef arg_tup(Py_BuildValue("(Os)", obtype_mod, signatures)); - if (type_key.isNull() || arg_tup.isNull() - || PyDict_SetItem(pyside_globals->arg_dict, type_key, arg_tup) < 0) + /* + * PYSIDE-996: Avoid string overflow in MSVC, which has a limit of + * 2**15 unicode characters (64 K memory). + * Instead of one huge string, we take a ssize_t that is the + * address of a string array. It will not be turned into a real + * string list until really used by Python. This is quite optimal. + */ + Shiboken::AutoDecRef numkey(Py_BuildValue("n", signatures)); + if (type_key.isNull() || numkey.isNull() + || PyDict_SetItem(pyside_globals->arg_dict, type_key, numkey) < 0) return -1; /* - * We also record a mapping from type key to type/module. This helps to + * We record also a mapping from type key to type/module. This helps to * lazily initialize the Py_LIMITED_API in name_key_to_func(). */ return PyDict_SetItem(pyside_globals->map_dict, type_key, obtype_mod) == 0 ? 0 : -1; @@ -856,7 +864,26 @@ init_module_2(void) } static PyObject * -PySide_BuildSignatureProps(PyObject *obtype_mod) +_address_to_stringlist(PyObject *numkey) +{ + ssize_t address = PyNumber_AsSsize_t(numkey, PyExc_ValueError); + if (address == -1 && PyErr_Occurred()) + return nullptr; + char **sig_strings = reinterpret_cast<char **>(address); + PyObject *res_list = PyList_New(0); + if (res_list == nullptr) + return nullptr; + for (; *sig_strings != nullptr; ++sig_strings) { + char *sig_str = *sig_strings; + Shiboken::AutoDecRef pystr(Py_BuildValue("s", sig_str)); + if (pystr.isNull() || PyList_Append(res_list, pystr) < 0) + return nullptr; + } + return res_list; +} + +static PyObject * +PySide_BuildSignatureProps(PyObject *type_key) { /* * Here is the second part of the function. @@ -865,11 +892,14 @@ PySide_BuildSignatureProps(PyObject *obtype_mod) * them by the function result. */ init_module_2(); - Shiboken::AutoDecRef type_key(GetTypeKey(obtype_mod)); - if (type_key.isNull()) + if (type_key == nullptr) + return nullptr; + PyObject *numkey = PyDict_GetItem(pyside_globals->arg_dict, type_key); + Shiboken::AutoDecRef strings(_address_to_stringlist(numkey)); + if (strings.isNull()) return nullptr; - PyObject *arg_tup = PyDict_GetItem(pyside_globals->arg_dict, type_key); - if (arg_tup == nullptr) + Shiboken::AutoDecRef arg_tup(Py_BuildValue("(OO)", type_key, strings.object())); + if (arg_tup.isNull()) return nullptr; PyObject *dict = PyObject_CallObject(pyside_globals->pyside_type_init_func, arg_tup); if (dict == nullptr) { @@ -890,7 +920,7 @@ static int _finish_nested_classes(PyObject *dict); static int _build_func_to_type(PyObject *obtype); static int -PySide_FinishSignatures(PyObject *module, const char *signatures) +PySide_FinishSignatures(PyObject *module, const char *signatures[]) { /* * Initialization of module functions and resolving of static methods. @@ -1030,7 +1060,7 @@ _build_func_to_type(PyObject *obtype) int SbkSpecial_Type_Ready(PyObject *module, PyTypeObject *type, - const char *signatures) + const char *signatures[]) { if (PyType_Ready(type) < 0) return -1; @@ -1044,7 +1074,7 @@ SbkSpecial_Type_Ready(PyObject *module, PyTypeObject *type, } void -FinishSignatureInitialization(PyObject *module, const char *signatures) +FinishSignatureInitialization(PyObject *module, const char *signatures[]) { /* * This function is called at the very end of a module initialization. |