Commit 3bdba45b authored by da-woods's avatar da-woods Committed by Stefan Behnel

Fixed crash with default arguments and bound fused functions (GH-3398)

Default arguments are now copied when the bound fused function is created.
parent 9cda69e9
...@@ -36,6 +36,7 @@ typedef struct { ...@@ -36,6 +36,7 @@ typedef struct {
// Dynamic default args and annotations // Dynamic default args and annotations
void *defaults; void *defaults;
int defaults_pyobjects; int defaults_pyobjects;
size_t defaults_size; // used by FusedFunction for copying defaults
int flags; int flags;
// Defaults info // Defaults info
...@@ -471,6 +472,7 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int f ...@@ -471,6 +472,7 @@ static PyObject *__Pyx_CyFunction_New(PyTypeObject *type, PyMethodDef *ml, int f
op->func_code = code; op->func_code = code;
// Dynamic Default args // Dynamic Default args
op->defaults_pyobjects = 0; op->defaults_pyobjects = 0;
op->defaults_size = 0;
op->defaults = NULL; op->defaults = NULL;
op->defaults_tuple = NULL; op->defaults_tuple = NULL;
op->defaults_kwdict = NULL; op->defaults_kwdict = NULL;
...@@ -755,6 +757,7 @@ static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t ...@@ -755,6 +757,7 @@ static CYTHON_INLINE void *__Pyx_CyFunction_InitDefaults(PyObject *func, size_t
return PyErr_NoMemory(); return PyErr_NoMemory();
memset(m->defaults, 0, size); memset(m->defaults, 0, size);
m->defaults_pyobjects = pyobjects; m->defaults_pyobjects = pyobjects;
m->defaults_size = size;
return m->defaults; return m->defaults;
} }
...@@ -904,6 +907,26 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type) ...@@ -904,6 +907,26 @@ __pyx_FusedFunction_descr_get(PyObject *self, PyObject *obj, PyObject *type)
if (!meth) if (!meth)
return NULL; return NULL;
// defaults needs copying fully rather than just copying the pointer
// since otherwise it will be freed on destruction of meth despite
// belonging to func rather than meth
if (func->func.defaults) {
PyObject **pydefaults;
int i;
if (!__Pyx_CyFunction_InitDefaults((PyObject*)meth,
func->func.defaults_size,
func->func.defaults_pyobjects)) {
Py_XDECREF((PyObject*)meth);
return NULL;
}
memcpy(meth->func.defaults, func->func.defaults, func->func.defaults_size);
pydefaults = __Pyx_CyFunction_Defaults(PyObject *, meth);
for (i = 0; i < meth->func.defaults_pyobjects; i++)
Py_XINCREF(pydefaults[i]);
}
Py_XINCREF(func->func.func_classobj); Py_XINCREF(func->func.func_classobj);
meth->func.func_classobj = func->func.func_classobj; meth->func.func_classobj = func->func.func_classobj;
......
...@@ -405,3 +405,31 @@ def test_decorators(cython.floating arg): ...@@ -405,3 +405,31 @@ def test_decorators(cython.floating arg):
>>> test_decorators.order >>> test_decorators.order
[3, 2, 1] [3, 2, 1]
""" """
@cython.binding(True)
def bind_me(self, cython.floating a=1.):
return a
cdef class HasBound:
"""
Using default arguments of bound specialized fused functions used to cause a segfault
https://github.com/cython/cython/issues/3370
>>> inst = HasBound()
>>> inst.func()
1.0
>>> inst.func(2)
2.0
>>> inst.func_fused()
1.0
>>> inst.func_fused(2.)
2.0
>>> bind_me.__defaults__
(1.0,)
>>> inst.func.__defaults__
(1.0,)
>>> inst.func_fused.__defaults__
(1.0,)
"""
func = bind_me[float]
func_fused = bind_me
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment