diff --git a/Stackless/changelog.txt b/Stackless/changelog.txt index a1ca85d6f373ac..8dd92930d4dd91 100644 --- a/Stackless/changelog.txt +++ b/Stackless/changelog.txt @@ -9,6 +9,10 @@ What's New in Stackless 3.X.X? *Release date: 20XX-XX-XX* +- https://github.com/stackless-dev/stackless/issues/265 + Avoid undefined behavior, if Stackless classes implement __reduce__() and + __reduce_ex__() using a single C-function. + - https://github.com/stackless-dev/stackless/issues/265 Fix C-API functions PyChannel_Send(), PyChannel_Send_nr(), PyChannel_Receive(), PyChannel_Receive_nr(), and diff --git a/Stackless/core/cframeobject.c b/Stackless/core/cframeobject.c index fe2ce011a39831..dc1a8500e85a8b 100644 --- a/Stackless/core/cframeobject.c +++ b/Stackless/core/cframeobject.c @@ -133,7 +133,7 @@ static PyObject * execute_soft_switchable_func(PyFrameObject *, int, PyObject *) SLP_DEF_INVALID_EXEC(execute_soft_switchable_func) static PyObject * -cframe_reduce(PyCFrameObject *cf) +cframe_reduce(PyCFrameObject *cf, PyObject *value) { PyObject *res = NULL, *exec_name = NULL; PyObject *params = NULL; @@ -141,6 +141,11 @@ cframe_reduce(PyCFrameObject *cf) PyObject *obs[3]; long i, n; + if (value && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "__reduce_ex__ argument should be an integer"); + return NULL; + } + if (cf->f_execute == execute_soft_switchable_func) { exec_name = (PyObject *) cf->any2; assert(cf->any2); @@ -240,7 +245,7 @@ cframe_setstate(PyObject *self, PyObject *args) static PyMethodDef cframe_methods[] = { {"__reduce__", (PyCFunction)cframe_reduce, METH_NOARGS, NULL}, - {"__reduce_ex__", (PyCFunction)cframe_reduce, METH_VARARGS, NULL}, + {"__reduce_ex__", (PyCFunction)cframe_reduce, METH_O, NULL}, {"__setstate__", (PyCFunction)cframe_setstate, METH_O, NULL}, {NULL, NULL} }; @@ -386,8 +391,13 @@ slp_cframe_fini(void) */ static PyObject * -function_declaration_reduce(PyStacklessFunctionDeclarationObject *self) +function_declaration_reduce(PyStacklessFunctionDeclarationObject *self, PyObject *value) { + if (value && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "__reduce_ex__ argument should be an integer"); + return NULL; + } + if (self->name == NULL || *self->name == '\0') { PyErr_SetString(PyExc_SystemError, "no function name"); return NULL; @@ -397,7 +407,7 @@ function_declaration_reduce(PyStacklessFunctionDeclarationObject *self) static PyMethodDef function_declaration_methods[] = { {"__reduce__", (PyCFunction)function_declaration_reduce, METH_NOARGS, NULL}, - {"__reduce_ex__", (PyCFunction)function_declaration_reduce, METH_VARARGS, NULL}, + {"__reduce_ex__", (PyCFunction)function_declaration_reduce, METH_O, NULL}, {NULL, NULL} }; diff --git a/Stackless/module/channelobject.c b/Stackless/module/channelobject.c index b7f8173813373f..1d524323b4da33 100644 --- a/Stackless/module/channelobject.c +++ b/Stackless/module/channelobject.c @@ -1104,12 +1104,17 @@ PyDoc_STRVAR(channel_reduce__doc__, "channel.__reduce__() -- currently does not distinguish threads."); static PyObject * -channel_reduce(PyChannelObject * ch) +channel_reduce(PyChannelObject * ch, PyObject *value) { PyObject *tup = NULL, *lis = NULL; PyTaskletObject *t; int i, n; + if (value && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "__reduce_ex__ argument should be an integer"); + return NULL; + } + lis = PyList_New(0); if (lis == NULL) goto err_exit; t = ch->head; @@ -1188,7 +1193,7 @@ channel_methods[] = { channel_open__doc__}, {"__reduce__", (PCF)channel_reduce, METH_NOARGS, channel_reduce__doc__}, - {"__reduce_ex__", (PCF)channel_reduce, METH_VARARGS, + {"__reduce_ex__", (PCF)channel_reduce, METH_O, channel_reduce__doc__}, {"__setstate__", (PCF)channel_setstate, METH_O, channel_setstate__doc__}, diff --git a/Stackless/module/scheduling.c b/Stackless/module/scheduling.c index 4f8a39d4957e14..e10dfef32d07ed 100644 --- a/Stackless/module/scheduling.c +++ b/Stackless/module/scheduling.c @@ -216,10 +216,15 @@ slp_bomb_explode(PyObject *_bomb) } static PyObject * -bomb_reduce(PyBombObject *bomb) +bomb_reduce(PyBombObject *bomb, PyObject *value) { PyObject *tup; + if (value && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "__reduce_ex__ argument should be an integer"); + return NULL; + } + tup = slp_into_tuple_with_nulls(&bomb->curexc_type, 3); if (tup != NULL) tup = Py_BuildValue("(O()O)", &PyBomb_Type, tup); @@ -246,7 +251,7 @@ static PyMemberDef bomb_members[] = { static PyMethodDef bomb_methods[] = { {"__reduce__", (PyCFunction)bomb_reduce, METH_NOARGS}, - {"__reduce_ex__", (PyCFunction)bomb_reduce, METH_VARARGS}, + {"__reduce_ex__", (PyCFunction)bomb_reduce, METH_O}, {"__setstate__", (PyCFunction)bomb_setstate, METH_O}, {NULL, NULL} /* sentinel */ }; diff --git a/Stackless/module/stacklessmodule.c b/Stackless/module/stacklessmodule.c index f723ea0b44a17c..a6a4472bd083e1 100644 --- a/Stackless/module/stacklessmodule.c +++ b/Stackless/module/stacklessmodule.c @@ -855,8 +855,13 @@ get_thread_info(PyObject *self, PyObject *args) } static PyObject * -slpmodule_reduce(PyObject *self) +slpmodule_reduce(PyObject *self, PyObject *value) { + if (value && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "__reduce_ex__ argument should be an integer"); + return NULL; + } + return PyUnicode_FromString("_stackless"); } @@ -1709,7 +1714,7 @@ static PyMethodDef stackless_methods[] = { _get_all_objects__doc__}, #endif {"__reduce__", (PCF)slpmodule_reduce, METH_NOARGS, NULL}, - {"__reduce_ex__", (PCF)slpmodule_reduce, METH_VARARGS, NULL}, + {"__reduce_ex__", (PCF)slpmodule_reduce, METH_O, NULL}, {"getdebug", (PCF)slpmodule_getdebug, METH_NOARGS, slpmodule_getdebug__doc__}, {"getuncollectables", (PCF)slpmodule_getuncollectables, METH_NOARGS, diff --git a/Stackless/module/taskletobject.c b/Stackless/module/taskletobject.c index 958f4d4d98accc..5ee791d76c7c15 100644 --- a/Stackless/module/taskletobject.c +++ b/Stackless/module/taskletobject.c @@ -612,7 +612,7 @@ simply the tasklet() call without parameters. */ static PyObject * -tasklet_reduce(PyTaskletObject * t) +tasklet_reduce(PyTaskletObject * t, PyObject *value) { PyObject *tup = NULL, *lis = NULL; PyFrameObject *f; @@ -620,6 +620,11 @@ tasklet_reduce(PyTaskletObject * t) PyObject *exc_type, *exc_value, *exc_traceback, *exc_info; PyObject *context = NULL; + if (value && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "__reduce_ex__ argument should be an integer"); + return NULL; + } + if (ts && t == ts->st.current) RUNTIME_ERROR("You cannot __reduce__ the tasklet which is" " current.", NULL); @@ -2580,7 +2585,7 @@ static PyMethodDef tasklet_methods[] = { tasklet_setup__doc__}, {"__reduce__", (PCF)tasklet_reduce, METH_NOARGS, tasklet_reduce__doc__}, - {"__reduce_ex__", (PCF)tasklet_reduce, METH_VARARGS, + {"__reduce_ex__", (PCF)tasklet_reduce, METH_O, tasklet_reduce__doc__}, {"__setstate__", (PCF)tasklet_setstate, METH_O, tasklet_setstate__doc__},