diff options
Diffstat (limited to 'Objects/call.c')
-rw-r--r-- | Objects/call.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/Objects/call.c b/Objects/call.c index 7d91789..8a60b3e 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -322,8 +322,7 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack, assert(nargs >= 0); assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); assert((nargs == 0 && nkwargs == 0) || stack != NULL); - /* kwnames must only contains str strings, no subclass, and all keys must - be unique */ + /* kwnames must only contain strings and all keys must be unique */ if (co->co_kwonlyargcount == 0 && nkwargs == 0 && (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) @@ -943,12 +942,12 @@ _PyStack_AsDict(PyObject *const *values, PyObject *kwnames) vector; return NULL with exception set on error. Return the keyword names tuple in *p_kwnames. - The newly allocated argument vector supports PY_VECTORCALL_ARGUMENTS_OFFSET. + This also checks that all keyword names are strings. If not, a TypeError is + raised. - When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) + The newly allocated argument vector supports PY_VECTORCALL_ARGUMENTS_OFFSET. - The type of keyword keys is not checked, these checks should be done - later (ex: _PyArg_ParseStackAndKeywords). */ + When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) */ static PyObject *const * _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject **p_kwnames) @@ -994,7 +993,9 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, called in the performance critical hot code. */ Py_ssize_t pos = 0, i = 0; PyObject *key, *value; + unsigned long keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; while (PyDict_Next(kwargs, &pos, &key, &value)) { + keys_are_strings &= Py_TYPE(key)->tp_flags; Py_INCREF(key); Py_INCREF(value); PyTuple_SET_ITEM(kwnames, i, key); @@ -1002,6 +1003,18 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, i++; } + /* keys_are_strings has the value Py_TPFLAGS_UNICODE_SUBCLASS if that + * flag is set for all keys. Otherwise, keys_are_strings equals 0. + * We do this check once at the end instead of inside the loop above + * because it simplifies the deallocation in the failing case. + * It happens to also make the loop above slightly more efficient. */ + if (!keys_are_strings) { + PyErr_SetString(PyExc_TypeError, + "keywords must be strings"); + _PyStack_UnpackDict_Free(stack, nargs, kwnames); + return NULL; + } + *p_kwnames = kwnames; return stack; } |