Ticket #736 (closed defect: fixed)
Crash when unpacking default arguments into closure variables
| Reported by: | scoder | Owned by: | scoder |
|---|---|---|---|
| Priority: | critical | Milestone: | 0.15.1 |
| Component: | Code Generation | Keywords: | |
| Cc: |
Description (last modified by scoder) (diff)
The following crashes in the argument unpacking code due to refcounting issues:
def default_args_for_closure(a=1, b=2):
"""
>>> default_args_for_closure()()
(1, 2)
>>> default_args_for_closure(1, 2)()
(1, 2)
>>> default_args_for_closure(2)()
(2, 2)
>>> default_args_for_closure(8,9)()
(8, 9)
>>> default_args_for_closure(7, b=6)()
(7, 6)
>>> default_args_for_closure(a=5, b=4)()
(5, 4)
>>> default_args_for_closure(b=5, a=6)()
(6, 5)
"""
def func():
return a,b
return func
The generated C code is this:
if (unlikely(__pyx_kwds)) {
Py_ssize_t kw_args = PyDict_Size(__pyx_kwds);
PyObject* values[2] = {0,0};
values[0] = ((PyObject *)__pyx_int_1);
values[1] = ((PyObject *)__pyx_int_2);
switch (PyTuple_GET_SIZE(__pyx_args)) {
case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
case 0: break;
default: goto __pyx_L5_argtuple_error;
}
switch (PyTuple_GET_SIZE(__pyx_args)) {
case 0:
if (kw_args > 0) {
PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__a);
if (value) { values[0] = value; kw_args--; }
}
case 1:
if (kw_args > 0) {
PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__b);
if (value) { values[1] = value; kw_args--; }
}
}
if (unlikely(kw_args > 0)) {
if (unlikely(__Pyx_ParseOptionalKeywords(/*...*/) /*...*/
}
__Pyx_INCREF(values[0]);
__pyx_cur_scope->__pyx_v_a = values[0];
__Pyx_INCREF(values[1]);
__pyx_cur_scope->__pyx_v_b = values[1];
} else {
__pyx_cur_scope->__pyx_v_a = ((PyObject *)__pyx_int_1);
__pyx_cur_scope->__pyx_v_b = ((PyObject *)__pyx_int_2);
switch (PyTuple_GET_SIZE(__pyx_args)) {
case 2: __Pyx_INCREF(PyTuple_GET_ITEM(__pyx_args, 1));
__pyx_cur_scope->__pyx_v_b = PyTuple_GET_ITEM(__pyx_args, 1);
case 1: __Pyx_INCREF(PyTuple_GET_ITEM(__pyx_args, 0));
__pyx_cur_scope->__pyx_v_a = PyTuple_GET_ITEM(__pyx_args, 0);
case 0: break;
default: goto __pyx_L5_argtuple_error;
}
}
goto __pyx_L4_argument_unpacking_done;
__pyx_L5_argtuple_error:;
__Pyx_RaiseArgtupleInvalid(/*...*/);
__pyx_L3_error:;
__Pyx_AddTraceback(/*...*/);
__Pyx_XDECREF(__pyx_cur_scope->__pyx_v_a); __pyx_cur_scope->__pyx_v_a = 0;
__Pyx_XDECREF(__pyx_cur_scope->__pyx_v_b); __pyx_cur_scope->__pyx_v_b = 0;
__Pyx_DECREF(((PyObject *)__pyx_cur_scope));
__Pyx_RefNannyFinishContext();
return NULL;
__pyx_L4_argument_unpacking_done:;
__Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_a);
__Pyx_GIVEREF(__pyx_cur_scope->__pyx_v_b);
The optimised tuple-unpacking-only case at the end does not INCREF the default arguments.
Change History
Note: See
TracTickets for help on using
tickets.
