Skip to content

Commit 7c0f498

Browse files
committed
Change initialize_locals(steal=true) and _PyTuple_FromArraySteal to consume the argument references regardless of whether they succeed or fail.
1 parent 5cc5442 commit 7c0f498

File tree

2 files changed

+50
-45
lines changed

2 files changed

+50
-45
lines changed

Objects/tupleobject.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,9 +490,11 @@ _PyTuple_FromArraySteal(PyObject *const *src, Py_ssize_t n)
490490
if (n == 0) {
491491
return tuple_get_empty();
492492
}
493-
494493
PyTupleObject *tuple = tuple_alloc(n);
495494
if (tuple == NULL) {
495+
for (Py_ssize_t i = 0; i < n; i++) {
496+
Py_DECREF(src[i]);
497+
}
496498
return NULL;
497499
}
498500
PyObject **dst = tuple->ob_item;

Python/ceval.c

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4610,23 +4610,19 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46104610
int is_generator = code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
46114611
if (!is_generator) {
46124612
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : PyFunction_GET_GLOBALS(function);
4613+
STACK_SHRINK(oparg);
46134614
InterpreterFrame *new_frame = _PyEvalFramePushAndInit(
46144615
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(function), locals,
4615-
stack_pointer-oparg,
4616+
stack_pointer,
46164617
nargs, kwnames, 1);
4617-
if (new_frame == NULL) {
4618-
// When we exit here, we own all variables in the stack
4619-
// (the frame creation has not stolen any variable) so
4620-
// we need to clean the whole stack (done in the
4621-
// "error" label).
4622-
goto error;
4623-
}
4624-
4625-
STACK_SHRINK(oparg + stackadj);
4618+
STACK_SHRINK(stackadj);
46264619
// The frame has stolen all the arguments from the stack,
46274620
// so there is no need to clean them up.
46284621
Py_XDECREF(kwnames);
46294622
Py_DECREF(function);
4623+
if (new_frame == NULL) {
4624+
goto error;
4625+
}
46304626
_PyFrame_SetStackPointer(frame, stack_pointer);
46314627
new_frame->depth = frame->depth + 1;
46324628
tstate->frame = frame = new_frame;
@@ -5397,7 +5393,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
53975393
if (co->co_flags & CO_VARKEYWORDS) {
53985394
kwdict = PyDict_New();
53995395
if (kwdict == NULL) {
5400-
goto fail;
5396+
goto fail_early;
54015397
}
54025398
i = total_args;
54035399
if (co->co_flags & CO_VARARGS) {
@@ -5436,11 +5432,19 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
54365432
u = _PyTuple_FromArray(args + n, argcount - n);
54375433
}
54385434
if (u == NULL) {
5439-
goto fail;
5435+
goto fail_post_positional;
54405436
}
54415437
assert(localsplus[total_args] == NULL);
54425438
localsplus[total_args] = u;
54435439
}
5440+
else if (argcount > n) {
5441+
/* Too many postional args. Error is reported later */
5442+
if (steal_args) {
5443+
for (j = n; j < argcount; j++) {
5444+
Py_DECREF(args[j]);
5445+
}
5446+
}
5447+
}
54445448

54455449
/* Handle keyword arguments */
54465450
if (kwnames != NULL) {
@@ -5455,7 +5459,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
54555459
_PyErr_Format(tstate, PyExc_TypeError,
54565460
"%U() keywords must be strings",
54575461
con->fc_qualname);
5458-
goto fail;
5462+
goto kw_fail;
54595463
}
54605464

54615465
/* Speed hack: do raw pointer compares. As names are
@@ -5476,7 +5480,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
54765480
goto kw_found;
54775481
}
54785482
else if (cmp < 0) {
5479-
goto fail;
5483+
goto kw_fail;
54805484
}
54815485
}
54825486

@@ -5488,29 +5492,38 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
54885492
kwcount, kwnames,
54895493
con->fc_qualname))
54905494
{
5491-
goto fail;
5495+
goto kw_fail;
54925496
}
54935497

54945498
_PyErr_Format(tstate, PyExc_TypeError,
54955499
"%U() got an unexpected keyword argument '%S'",
54965500
con->fc_qualname, keyword);
5497-
goto fail;
5501+
goto kw_fail;
54985502
}
54995503

55005504
if (PyDict_SetItem(kwdict, keyword, value) == -1) {
5501-
goto fail;
5505+
goto kw_fail;
55025506
}
55035507
if (steal_args) {
55045508
Py_DECREF(value);
55055509
}
55065510
continue;
55075511

5512+
kw_fail:
5513+
if (steal_args) {
5514+
for (;i < kwcount; i++) {
5515+
PyObject *value = args[i+argcount];
5516+
Py_DECREF(value);
5517+
}
5518+
}
5519+
goto fail_late;
5520+
55085521
kw_found:
55095522
if (localsplus[j] != NULL) {
55105523
_PyErr_Format(tstate, PyExc_TypeError,
55115524
"%U() got multiple values for argument '%S'",
55125525
con->fc_qualname, keyword);
5513-
goto fail;
5526+
goto kw_fail;
55145527
}
55155528
if (!steal_args) {
55165529
Py_INCREF(value);
@@ -5523,7 +5536,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
55235536
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
55245537
too_many_positional(tstate, co, argcount, con->fc_defaults, localsplus,
55255538
con->fc_qualname);
5526-
goto fail;
5539+
goto fail_late;
55275540
}
55285541

55295542
/* Add missing positional arguments (copy default values from defs) */
@@ -5539,7 +5552,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
55395552
if (missing) {
55405553
missing_arguments(tstate, co, missing, defcount, localsplus,
55415554
con->fc_qualname);
5542-
goto fail;
5555+
goto fail_late;
55435556
}
55445557
if (n > m)
55455558
i = n - m;
@@ -5572,15 +5585,15 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
55725585
continue;
55735586
}
55745587
else if (_PyErr_Occurred(tstate)) {
5575-
goto fail;
5588+
goto fail_late;
55765589
}
55775590
}
55785591
missing++;
55795592
}
55805593
if (missing) {
55815594
missing_arguments(tstate, co, missing, -1, localsplus,
55825595
con->fc_qualname);
5583-
goto fail;
5596+
goto fail_late;
55845597
}
55855598
}
55865599

@@ -5593,33 +5606,23 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
55935606

55945607
return 0;
55955608

5596-
fail: /* Jump here from prelude on failure */
5609+
fail_early:
55975610
if (steal_args) {
5598-
// If we failed to initialize locals, make sure the caller still own all the
5599-
// arguments that were on the stack. We need to increment the reference count
5600-
// of everything we copied (everything in localsplus) that came from the stack
5601-
// (everything that is present in the "args" array).
5602-
Py_ssize_t kwcount = kwnames != NULL ? PyTuple_GET_SIZE(kwnames) : 0;
5603-
for (Py_ssize_t k=0; k < total_args; k++) {
5604-
PyObject* arg = localsplus[k];
5605-
for (Py_ssize_t j=0; j < argcount + kwcount; j++) {
5606-
if (args[j] == arg) {
5607-
Py_XINCREF(arg);
5608-
break;
5609-
}
5610-
}
5611+
for (j = 0; j < argcount; j++) {
5612+
Py_DECREF(args[j]);
56115613
}
5612-
// Restore all the **kwargs we placed into the kwargs dictionary
5613-
if (kwdict) {
5614-
PyObject *key, *value;
5615-
Py_ssize_t pos = 0;
5616-
while (PyDict_Next(kwdict, &pos, &key, &value)) {
5617-
Py_INCREF(value);
5618-
}
5614+
}
5615+
/* fall through */
5616+
fail_post_positional:
5617+
if (steal_args) {
5618+
Py_ssize_t kwcount = kwnames != NULL ? PyTuple_GET_SIZE(kwnames) : 0;
5619+
for (j = argcount; j < argcount+kwcount; j++) {
5620+
Py_DECREF(args[j]);
56195621
}
56205622
}
5623+
/* fall through */
5624+
fail_late:
56215625
return -1;
5622-
56235626
}
56245627

56255628
static InterpreterFrame *

0 commit comments

Comments
 (0)