Skip to content

Commit da845ba

Browse files
committed
bpo-45256: Fix cleanup of stolen locals for Python-to-Python calls
1 parent 560a79f commit da845ba

File tree

1 file changed

+24
-10
lines changed

1 file changed

+24
-10
lines changed

Python/ceval.c

+24-10
Original file line numberDiff line numberDiff line change
@@ -5619,6 +5619,30 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
56195619
return 0;
56205620

56215621
fail: /* Jump here from prelude on failure */
5622+
if (steal_args) {
5623+
// If we failed to initialize locals, make sure the caller still own all the
5624+
// arguments that were on the stack. We need to increment the reference count
5625+
// of everything we copied (everything in localsplus) that came from the stack
5626+
// (everything that is present in the "args" array).
5627+
Py_ssize_t kwcount = kwnames != NULL ? PyTuple_GET_SIZE(kwnames) : 0;
5628+
for (Py_ssize_t k=0; k < total_args; k++) {
5629+
PyObject* arg = localsplus[k];
5630+
for (Py_ssize_t j=0; j < argcount + kwcount; j++) {
5631+
if (args[j] == arg) {
5632+
Py_XINCREF(arg);
5633+
break;
5634+
}
5635+
}
5636+
}
5637+
// Restore all the **kwargs we placed into the kwargs dictionary
5638+
if (kwdict) {
5639+
PyObject *key, *value;
5640+
Py_ssize_t pos = 0;
5641+
while (PyDict_Next(kwdict, &pos, &key, &value)) {
5642+
Py_INCREF(value);
5643+
}
5644+
}
5645+
}
56225646
return -1;
56235647

56245648
}
@@ -5683,16 +5707,6 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
56835707
}
56845708
PyObject **localsarray = _PyFrame_GetLocalsArray(frame);
56855709
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames, steal_args)) {
5686-
if (steal_args) {
5687-
// If we failed to initialize locals, make sure the caller still own all the
5688-
// arguments. Notice that we only need to increase the reference count of the
5689-
// *valid* arguments (i.e. the ones that fit into the frame).
5690-
PyCodeObject *co = (PyCodeObject*)con->fc_code;
5691-
const size_t total_args = co->co_argcount + co->co_kwonlyargcount;
5692-
for (size_t i = 0; i < Py_MIN(argcount, total_args); i++) {
5693-
Py_XINCREF(frame->localsplus[i]);
5694-
}
5695-
}
56965710
_PyFrame_Clear(frame, 0);
56975711
return NULL;
56985712
}

0 commit comments

Comments
 (0)