Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b728105

Browse files
Issue #27213: Fixed different issues with reworked CALL_FUNCTION* opcodes.
* BUILD_TUPLE_UNPACK and BUILD_MAP_UNPACK_WITH_CALL no longer generated with single tuple or dict. * Restored more informative error messages for incorrect var-positional and var-keyword arguments. * Removed code duplications in _PyEval_EvalCodeWithName(). * Removed redundant runtime checks and parameters in _PyStack_AsDict(). * Added a workaround and enabled previously disabled test in test_traceback. * Removed dead code from the dis module.
1 parent 29097d5 commit b728105

10 files changed

Lines changed: 3429 additions & 3472 deletions

File tree

Include/abstract.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
275275

276276
PyAPI_FUNC(PyObject *) _PyStack_AsDict(
277277
PyObject **values,
278-
Py_ssize_t nkwargs,
279-
PyObject *kwnames,
280-
PyObject *func);
278+
PyObject *kwnames);
281279

282280
/* Convert (args, nargs, kwargs) into a (stack, nargs, kwnames).
283281

Lib/dis.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,6 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
314314
argrepr = argval
315315
elif op in hasfree:
316316
argval, argrepr = _get_name_info(arg, cells)
317-
elif op in hasnargs: # unused
318-
argrepr = "%d positional, %d keyword pair" % (arg%256, arg//256)
319317
yield Instruction(opname[op], op,
320318
arg, argval, argrepr,
321319
offset, starts_line, is_jump_target)

Lib/test/test_extcall.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
>>> g(*Nothing())
119119
Traceback (most recent call last):
120120
...
121-
TypeError: 'Nothing' object is not iterable
121+
TypeError: g() argument after * must be an iterable, not Nothing
122122
123123
>>> class Nothing:
124124
... def __len__(self): return 5
@@ -127,7 +127,7 @@
127127
>>> g(*Nothing())
128128
Traceback (most recent call last):
129129
...
130-
TypeError: 'Nothing' object is not iterable
130+
TypeError: g() argument after * must be an iterable, not Nothing
131131
132132
>>> class Nothing():
133133
... def __len__(self): return 5
@@ -231,32 +231,34 @@
231231
>>> h(*h)
232232
Traceback (most recent call last):
233233
...
234-
TypeError: 'function' object is not iterable
234+
TypeError: h() argument after * must be an iterable, not function
235235
236236
>>> dir(*h)
237237
Traceback (most recent call last):
238238
...
239-
TypeError: 'function' object is not iterable
239+
TypeError: dir() argument after * must be an iterable, not function
240240
241241
>>> None(*h)
242242
Traceback (most recent call last):
243243
...
244-
TypeError: 'function' object is not iterable
244+
TypeError: NoneType object argument after * must be an iterable, \
245+
not function
245246
246247
>>> h(**h)
247248
Traceback (most recent call last):
248249
...
249-
TypeError: 'function' object is not a mapping
250+
TypeError: h() argument after ** must be a mapping, not function
250251
251252
>>> dir(**h)
252253
Traceback (most recent call last):
253254
...
254-
TypeError: 'function' object is not a mapping
255+
TypeError: dir() argument after ** must be a mapping, not function
255256
256257
>>> None(**h)
257258
Traceback (most recent call last):
258259
...
259-
TypeError: 'function' object is not a mapping
260+
TypeError: NoneType object argument after ** must be a mapping, \
261+
not function
260262
261263
>>> dir(b=1, **{'b': 1})
262264
Traceback (most recent call last):

Lib/test/test_traceback.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,6 @@ def prn():
304304
])
305305

306306
# issue 26823 - Shrink recursive tracebacks
307-
@unittest.skipIf(True, "FIXME: test broken, see issue #28050")
308307
def _check_recursive_traceback_display(self, render_exc):
309308
# Always show full diffs when this test fails
310309
# Note that rearranging things may require adjusting
@@ -353,7 +352,7 @@ def f():
353352

354353
# Check the recursion count is roughly as expected
355354
rec_limit = sys.getrecursionlimit()
356-
self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-50, rec_limit))
355+
self.assertIn(int(re.search(r"\d+", actual[-2]).group()), range(rec_limit-60, rec_limit))
357356

358357
# Check a known (limited) number of recursive invocations
359358
def g(count=10):

Objects/abstract.c

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2367,9 +2367,9 @@ _PyObject_Call_Prepend(PyObject *func,
23672367
}
23682368

23692369
PyObject *
2370-
_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
2371-
PyObject *func)
2370+
_PyStack_AsDict(PyObject **values, PyObject *kwnames)
23722371
{
2372+
Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
23732373
PyObject *kwdict;
23742374
Py_ssize_t i;
23752375

@@ -2378,24 +2378,12 @@ _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
23782378
return NULL;
23792379
}
23802380

2381-
for (i=0; i < nkwargs; i++) {
2382-
int err;
2381+
for (i = 0; i < nkwargs; i++) {
23832382
PyObject *key = PyTuple_GET_ITEM(kwnames, i);
23842383
PyObject *value = *values++;
2385-
2386-
if (PyDict_GetItem(kwdict, key) != NULL) {
2387-
PyErr_Format(PyExc_TypeError,
2388-
"%.200s%s got multiple values "
2389-
"for keyword argument '%U'",
2390-
PyEval_GetFuncName(func),
2391-
PyEval_GetFuncDesc(func),
2392-
key);
2393-
Py_DECREF(kwdict);
2394-
return NULL;
2395-
}
2396-
2397-
err = PyDict_SetItem(kwdict, key, value);
2398-
if (err) {
2384+
assert(PyUnicode_CheckExact(key));
2385+
assert(PyDict_GetItem(kwdict, key) == NULL);
2386+
if (PyDict_SetItem(kwdict, key, value)) {
23992387
Py_DECREF(kwdict);
24002388
return NULL;
24012389
}
@@ -2479,7 +2467,7 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs,
24792467
}
24802468

24812469
if (nkwargs > 0) {
2482-
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
2470+
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
24832471
if (kwdict == NULL) {
24842472
return NULL;
24852473
}

Objects/methodobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ _PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
279279

280280
nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
281281
if (nkwargs > 0) {
282-
kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func);
282+
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
283283
if (kwdict == NULL) {
284284
return NULL;
285285
}

Python/ceval.c

Lines changed: 57 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -2513,14 +2513,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
25132513
TARGET(BUILD_LIST_UNPACK) {
25142514
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
25152515
Py_ssize_t i;
2516-
PyObject *sum;
2516+
PyObject *sum = PyList_New(0);
25172517
PyObject *return_value;
25182518

2519-
if (convert_to_tuple && oparg == 1 && PyTuple_CheckExact(TOP())) {
2520-
DISPATCH();
2521-
}
2522-
2523-
sum = PyList_New(0);
25242519
if (sum == NULL)
25252520
goto error;
25262521

@@ -2708,13 +2703,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
27082703
TARGET(BUILD_MAP_UNPACK) {
27092704
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
27102705
Py_ssize_t i;
2711-
PyObject *sum;
2712-
2713-
if (with_call && oparg == 1 && PyDict_CheckExact(TOP())) {
2714-
DISPATCH();
2715-
}
2716-
2717-
sum = PyDict_New();
2706+
PyObject *sum = PyDict_New();
27182707
if (sum == NULL)
27192708
goto error;
27202709

@@ -3290,11 +3279,53 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
32903279
PCALL(PCALL_ALL);
32913280
if (oparg & 0x01) {
32923281
kwargs = POP();
3282+
if (!PyDict_CheckExact(kwargs)) {
3283+
PyObject *d = PyDict_New();
3284+
if (d == NULL)
3285+
goto error;
3286+
if (PyDict_Update(d, kwargs) != 0) {
3287+
Py_DECREF(d);
3288+
/* PyDict_Update raises attribute
3289+
* error (percolated from an attempt
3290+
* to get 'keys' attribute) instead of
3291+
* a type error if its second argument
3292+
* is not a mapping.
3293+
*/
3294+
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
3295+
func = SECOND();
3296+
PyErr_Format(PyExc_TypeError,
3297+
"%.200s%.200s argument after ** "
3298+
"must be a mapping, not %.200s",
3299+
PyEval_GetFuncName(func),
3300+
PyEval_GetFuncDesc(func),
3301+
kwargs->ob_type->tp_name);
3302+
}
3303+
goto error;
3304+
}
3305+
Py_DECREF(kwargs);
3306+
kwargs = d;
3307+
}
32933308
assert(PyDict_CheckExact(kwargs));
32943309
}
32953310
callargs = POP();
3296-
assert(PyTuple_CheckExact(callargs));
32973311
func = TOP();
3312+
if (!PyTuple_Check(callargs)) {
3313+
if (Py_TYPE(callargs)->tp_iter == NULL &&
3314+
!PySequence_Check(callargs)) {
3315+
PyErr_Format(PyExc_TypeError,
3316+
"%.200s%.200s argument after * "
3317+
"must be an iterable, not %.200s",
3318+
PyEval_GetFuncName(func),
3319+
PyEval_GetFuncDesc(func),
3320+
callargs->ob_type->tp_name);
3321+
goto error;
3322+
}
3323+
Py_SETREF(callargs, PySequence_Tuple(callargs));
3324+
if (callargs == NULL) {
3325+
goto error;
3326+
}
3327+
}
3328+
assert(PyTuple_Check(callargs));
32983329

32993330
result = do_call_core(func, callargs, kwargs);
33003331
Py_DECREF(func);
@@ -3796,8 +3827,8 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
37963827
static PyObject *
37973828
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
37983829
PyObject **args, Py_ssize_t argcount,
3799-
PyObject **kws, Py_ssize_t kwcount,
3800-
PyObject *kwnames, PyObject **kwstack,
3830+
PyObject **kwnames, PyObject **kwargs,
3831+
Py_ssize_t kwcount, int kwstep,
38013832
PyObject **defs, Py_ssize_t defcount,
38023833
PyObject *kwdefs, PyObject *closure,
38033834
PyObject *name, PyObject *qualname)
@@ -3811,9 +3842,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
38113842
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
38123843
Py_ssize_t i, n;
38133844
PyObject *kwdict;
3814-
Py_ssize_t kwcount2 = kwnames == NULL ? 0 : PyTuple_GET_SIZE(kwnames);
3815-
3816-
assert((kwcount == 0) || (kws != NULL));
38173845

38183846
if (globals == NULL) {
38193847
PyErr_SetString(PyExc_SystemError,
@@ -3873,11 +3901,12 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
38733901
}
38743902
}
38753903

3876-
/* Handle keyword arguments passed as an array of (key, value) pairs */
3877-
for (i = 0; i < kwcount; i++) {
3904+
/* Handle keyword arguments passed as two strided arrays */
3905+
kwcount *= kwstep;
3906+
for (i = 0; i < kwcount; i += kwstep) {
38783907
PyObject **co_varnames;
3879-
PyObject *keyword = kws[2*i];
3880-
PyObject *value = kws[2*i + 1];
3908+
PyObject *keyword = kwnames[i];
3909+
PyObject *value = kwargs[i];
38813910
Py_ssize_t j;
38823911

38833912
if (keyword == NULL || !PyUnicode_Check(keyword)) {
@@ -3932,61 +3961,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
39323961
SETLOCAL(j, value);
39333962
}
39343963

3935-
/* Handle keyword arguments passed as keys tuple + values array */
3936-
for (i = 0; i < kwcount2; i++) {
3937-
PyObject **co_varnames;
3938-
PyObject *keyword = PyTuple_GET_ITEM(kwnames, i);
3939-
PyObject *value = kwstack[i];
3940-
int j;
3941-
if (keyword == NULL || !PyUnicode_Check(keyword)) {
3942-
PyErr_Format(PyExc_TypeError,
3943-
"%U() keywords must be strings",
3944-
co->co_name);
3945-
goto fail;
3946-
}
3947-
/* Speed hack: do raw pointer compares. As names are
3948-
normally interned this should almost always hit. */
3949-
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
3950-
for (j = 0; j < total_args; j++) {
3951-
PyObject *nm = co_varnames[j];
3952-
if (nm == keyword)
3953-
goto kw_found2;
3954-
}
3955-
/* Slow fallback, just in case */
3956-
for (j = 0; j < total_args; j++) {
3957-
PyObject *nm = co_varnames[j];
3958-
int cmp = PyObject_RichCompareBool(
3959-
keyword, nm, Py_EQ);
3960-
if (cmp > 0)
3961-
goto kw_found2;
3962-
else if (cmp < 0)
3963-
goto fail;
3964-
}
3965-
if (j >= total_args && kwdict == NULL) {
3966-
PyErr_Format(PyExc_TypeError,
3967-
"%U() got an unexpected "
3968-
"keyword argument '%S'",
3969-
co->co_name,
3970-
keyword);
3971-
goto fail;
3972-
}
3973-
if (PyDict_SetItem(kwdict, keyword, value) == -1) {
3974-
goto fail;
3975-
}
3976-
continue;
3977-
kw_found2:
3978-
if (GETLOCAL(j) != NULL) {
3979-
PyErr_Format(PyExc_TypeError,
3980-
"%U() got multiple "
3981-
"values for argument '%S'",
3982-
co->co_name,
3983-
keyword);
3984-
goto fail;
3985-
}
3986-
Py_INCREF(value);
3987-
SETLOCAL(j, value);
3988-
}
3989-
39903964
/* Check the number of positional arguments */
39913965
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) {
39923966
too_many_positional(co, argcount, defcount, fastlocals);
@@ -4138,8 +4112,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
41384112
{
41394113
return _PyEval_EvalCodeWithName(_co, globals, locals,
41404114
args, argcount,
4141-
kws, kwcount,
4142-
NULL, NULL,
4115+
kws, kws + 1, kwcount, 2,
41434116
defs, defcount,
41444117
kwdefs, closure,
41454118
NULL, NULL);
@@ -4923,8 +4896,9 @@ fast_function(PyObject *func, PyObject **stack,
49234896
}
49244897
return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
49254898
stack, nargs,
4926-
NULL, 0,
4927-
kwnames, stack + nargs,
4899+
nkwargs ? &PyTuple_GET_ITEM(kwnames, 0) : NULL,
4900+
stack + nargs,
4901+
nkwargs, 1,
49284902
d, (int)nd, kwdefs,
49294903
closure, name, qualname);
49304904
}
@@ -5014,8 +4988,7 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
50144988

50154989
result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
50164990
args, nargs,
5017-
k, nk,
5018-
NULL, NULL,
4991+
k, k + 1, nk, 2,
50194992
d, nd, kwdefs,
50204993
closure, name, qualname);
50214994
Py_XDECREF(kwtuple);

0 commit comments

Comments
 (0)