From 5a574b8417839b3867b3a5a728db2744056cd232 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Sat, 27 Oct 2018 23:07:53 +0200 Subject: [PATCH] Stackless issue #177: Fix prickelpit.c function slp_cannot_execute() I missed the C-fame case, when I changed the frame-function ref counting in Stackless issue #117. --- Include/frameobject.h | 18 ++++++++++++++++ Stackless/changelog.txt | 6 ++++++ Stackless/pickling/prickelpit.c | 38 ++++++++++++++++----------------- Stackless/pickling/prickelpit.h | 2 +- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/Include/frameobject.h b/Include/frameobject.h index 42f6586dd9637a..e541890c24b114 100644 --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -10,6 +10,24 @@ extern "C" { #ifdef STACKLESS typedef PyObject *(PyFrame_ExecFunc) (struct _frame *, int, PyObject *); +/* + * How to write frame execution functions: + * + * Special rule for frame execution functions: the function owns a reference to retval! + * + * PyObject * example(PyFrameObject *f, int exc, PyObject *retval) + * { + * PyThreadState *ts = PyThreadState_GET(); + * + * do something .... + * if you change retval, use Py_SETREF(retval, new_value) or + * Py_CLEAR(retval) + * + * SLP_STORE_NEXT_FRAME(ts, f->f_back); + * return retval; + * } + * + */ #endif typedef struct { diff --git a/Stackless/changelog.txt b/Stackless/changelog.txt index c62e5f70e21e26..e843066b0fffa4 100644 --- a/Stackless/changelog.txt +++ b/Stackless/changelog.txt @@ -9,6 +9,12 @@ What's New in Stackless 3.X.X? *Release date: 20XX-XX-XX* +- https://github.com/stackless-dev/stackless/issues/177 + Fix a crasher in prickelpit.c slp_cannot_execute(). + Stackless versions released after March 2017 can crash, if a program executes + an unpickled tasklet, that lost its C-state. Now Stackless always raises + RuntimeError. + - https://github.com/stackless-dev/stackless/issues/152 C-Python bpo30860 consolidates stateful C globals under a single struct. Stackless also moves its stateful C globals to the appropriate structures diff --git a/Stackless/pickling/prickelpit.c b/Stackless/pickling/prickelpit.c index b46c08a2064982..52a5b15fec7201 100644 --- a/Stackless/pickling/prickelpit.c +++ b/Stackless/pickling/prickelpit.c @@ -365,34 +365,34 @@ run_script(char *src, char *retname) */ PyObject * -slp_cannot_execute(PyFrameObject *f, char *exec_name, PyObject *retval) +slp_cannot_execute(PyFrameObject *f, const char *exec_name, PyObject *retval) { + /* + * Special rule for frame execution functions: we now own a reference to retval! + */ + /* * show an error message and raise exception. */ - PyObject *message; PyThreadState *tstate = PyThreadState_GET(); /* if we already have an exception, we keep it */ - if (retval == NULL) - goto err_exit; - - message = PyUnicode_FromFormat("cannot execute invalid frame with " - "'%.100s': frame had a C state that" - " can't be restored.", - exec_name); - if (message == NULL) { - /* try at least something */ - PyErr_SetString(PyExc_RuntimeError, - "invalid frame, cannot build error message."); - goto err_exit; + if (retval != NULL) { + Py_DECREF(retval); + PyErr_Format(PyExc_RuntimeError, "cannot execute invalid frame with " + "'%.100s': frame had a C state that" + " can't be restored.", + exec_name); } - PyErr_SetObject(PyExc_RuntimeError, message); - Py_DECREF(message); -err_exit: + SLP_STORE_NEXT_FRAME(tstate, f->f_back); - --tstate->recursion_depth; - Py_XDECREF(retval); + + if(PyFrame_Check(f)) { + /* Only real frames contribute to the recursion count. + * C-frames don't contribute, see tasklet_setstate(...) */ + --tstate->recursion_depth; + } + return NULL; } diff --git a/Stackless/pickling/prickelpit.h b/Stackless/pickling/prickelpit.h index d544f00a9a3a2a..1a9b3912ade2ce 100644 --- a/Stackless/pickling/prickelpit.h +++ b/Stackless/pickling/prickelpit.h @@ -20,7 +20,7 @@ int slp_find_execfuncs(PyTypeObject *type, PyObject *exec_name, PyObject * slp_find_execname(PyFrameObject *f, int *valid); -PyObject * slp_cannot_execute(PyFrameObject *f, char *exec_name, PyObject *retval); +PyObject * slp_cannot_execute(PyFrameObject *f, const char *exec_name, PyObject *retval); /* macros to define and use an invalid frame executor */