diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2017-08-03 08:37:15 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-03 08:37:15 (GMT) |
commit | 25e4f779d7ae9f37a1933cb5cbfad06e673c01f9 (patch) | |
tree | cf3671f5eed00c26f2ccef0634ff4ce556aac286 | |
parent | 49b2734bf12dc1cda80fd73d3ec8896ae3e362f2 (diff) | |
download | cpython-25e4f779d7ae9f37a1933cb5cbfad06e673c01f9.zip cpython-25e4f779d7ae9f37a1933cb5cbfad06e673c01f9.tar.gz cpython-25e4f779d7ae9f37a1933cb5cbfad06e673c01f9.tar.bz2 |
bpo-31071: Avoid masking original TypeError in call with * unpacking (#2957)
when other arguments are passed.
-rw-r--r-- | Lib/test/test_extcall.py | 16 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2017-07-31-13-28-53.bpo-31071.P9UBDy.rst | 2 | ||||
-rw-r--r-- | Python/ceval.c | 63 |
3 files changed, 52 insertions, 29 deletions
diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py index 043df01..2c18483 100644 --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -163,6 +163,10 @@ right error message? (Also check with other iterables.) Traceback (most recent call last): ... TypeError: myerror + >>> g(*range(1), *(broken() for i in range(1))) + Traceback (most recent call last): + ... + TypeError: myerror >>> class BrokenIterable1: ... def __iter__(self): @@ -172,6 +176,10 @@ right error message? (Also check with other iterables.) Traceback (most recent call last): ... TypeError: myerror + >>> g(*range(1), *BrokenIterable1()) + Traceback (most recent call last): + ... + TypeError: myerror >>> class BrokenIterable2: ... def __iter__(self): @@ -182,6 +190,10 @@ right error message? (Also check with other iterables.) Traceback (most recent call last): ... TypeError: myerror + >>> g(*range(1), *BrokenIterable2()) + Traceback (most recent call last): + ... + TypeError: myerror >>> class BrokenSequence: ... def __getitem__(self, idx): @@ -191,6 +203,10 @@ right error message? (Also check with other iterables.) Traceback (most recent call last): ... TypeError: myerror + >>> g(*range(1), *BrokenSequence()) + Traceback (most recent call last): + ... + TypeError: myerror Make sure that the function doesn't stomp the dictionary diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-07-31-13-28-53.bpo-31071.P9UBDy.rst b/Misc/NEWS.d/next/Core and Builtins/2017-07-31-13-28-53.bpo-31071.P9UBDy.rst new file mode 100644 index 0000000..c34d475 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-07-31-13-28-53.bpo-31071.P9UBDy.rst @@ -0,0 +1,2 @@ +Avoid masking original TypeError in call with * unpacking when other +arguments are passed. diff --git a/Python/ceval.c b/Python/ceval.c index be5cda5..9f732f5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -66,6 +66,8 @@ static void format_exc_unbound(PyCodeObject *co, int oparg); static PyObject * unicode_concatenate(PyObject *, PyObject *, PyFrameObject *, const _Py_CODEUNIT *); static PyObject * special_lookup(PyObject *, _Py_Identifier *); +static int check_args_iterable(PyObject *func, PyObject *vararg); +static void format_kwargs_mapping_error(PyObject *func, PyObject *kwargs); #define NAME_ERROR_MSG \ "name '%.200s' is not defined" @@ -2512,14 +2514,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) none_val = _PyList_Extend((PyListObject *)sum, PEEK(i)); if (none_val == NULL) { if (opcode == BUILD_TUPLE_UNPACK_WITH_CALL && - PyErr_ExceptionMatches(PyExc_TypeError)) { - PyObject *func = PEEK(1 + oparg); - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after * " - "must be an iterable, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - PEEK(i)->ob_type->tp_name); + PyErr_ExceptionMatches(PyExc_TypeError)) + { + check_args_iterable(PEEK(1 + oparg), PEEK(i)); } Py_DECREF(sum); goto error; @@ -2732,12 +2729,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) if (_PyDict_MergeEx(sum, arg, 2) < 0) { PyObject *func = PEEK(2 + oparg); if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after ** " - "must be a mapping, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - arg->ob_type->tp_name); + format_kwargs_mapping_error(func, arg); } else if (PyErr_ExceptionMatches(PyExc_KeyError)) { PyObject *exc, *val, *tb; @@ -3390,13 +3382,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) * is not a mapping. */ if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - func = SECOND(); - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after ** " - "must be a mapping, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - kwargs->ob_type->tp_name); + format_kwargs_mapping_error(SECOND(), kwargs); } Py_DECREF(kwargs); goto error; @@ -3409,14 +3395,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) callargs = POP(); func = TOP(); if (!PyTuple_CheckExact(callargs)) { - if (Py_TYPE(callargs)->tp_iter == NULL && - !PySequence_Check(callargs)) { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after * " - "must be an iterable, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - callargs->ob_type->tp_name); + if (check_args_iterable(func, callargs) < 0) { Py_DECREF(callargs); goto error; } @@ -5179,6 +5158,32 @@ import_all_from(PyObject *locals, PyObject *v) return err; } +static int +check_args_iterable(PyObject *func, PyObject *args) +{ + if (args->ob_type->tp_iter == NULL && !PySequence_Check(args)) { + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after * " + "must be an iterable, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + args->ob_type->tp_name); + return -1; + } + return 0; +} + +static void +format_kwargs_mapping_error(PyObject *func, PyObject *kwargs) +{ + PyErr_Format(PyExc_TypeError, + "%.200s%.200s argument after ** " + "must be a mapping, not %.200s", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + kwargs->ob_type->tp_name); +} + static void format_exc_check_arg(PyObject *exc, const char *format_str, PyObject *obj) { |