Skip to content

Commit

Permalink
Stackless issue python#265: fix __reduce__ / __reduce_ex__
Browse files Browse the repository at this point in the history
Avoid undefined behavior, if Stackless classes implement __reduce__()
and __reduce_ex__() using a single C-function.
__reduce_ex__ now checks the type of its argument.
  • Loading branch information
Anselm Kruis authored and akruis committed Jun 10, 2021
1 parent 04cff9c commit 10c8679
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 12 deletions.
4 changes: 4 additions & 0 deletions Stackless/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 14 additions & 4 deletions Stackless/core/cframeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,19 @@ 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;
int valid = 1;
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);
Expand Down Expand Up @@ -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}
};
Expand Down Expand Up @@ -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;
Expand All @@ -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}
};

Expand Down
9 changes: 7 additions & 2 deletions Stackless/module/channelobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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__},
Expand Down
9 changes: 7 additions & 2 deletions Stackless/module/scheduling.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 */
};
Expand Down
9 changes: 7 additions & 2 deletions Stackless/module/stacklessmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down Expand Up @@ -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,
Expand Down
9 changes: 7 additions & 2 deletions Stackless/module/taskletobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,14 +612,19 @@ 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;
PyThreadState *ts = t->cstate->tstate;
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);
Expand Down Expand Up @@ -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__},
Expand Down

0 comments on commit 10c8679

Please sign in to comment.