diff --git a/Stackless/changelog.txt b/Stackless/changelog.txt index 8ee8a469f04086..1d0eaffafa68de 100644 --- a/Stackless/changelog.txt +++ b/Stackless/changelog.txt @@ -74,6 +74,7 @@ What's New in Stackless 3.X.X? - https://bitbucket.org/stackless-dev/stackless/issues/107 Improve unpickling of traceback objects. Stackless now reconstructs the frame.f_back linkage in frames directly referenced by traceback objects. + Stackless no longer pretends to be able to pickle arbitrary frame objects. - https://bitbucket.org/stackless-dev/stackless/issues/110 Remove the already non functional remains of psyco support. diff --git a/Stackless/pickling/prickelpit.c b/Stackless/pickling/prickelpit.c index 9c873a46ca6f44..b3795807105b73 100644 --- a/Stackless/pickling/prickelpit.c +++ b/Stackless/pickling/prickelpit.c @@ -209,6 +209,64 @@ slp_reduce_frame(PyFrameObject * frame) { return PyObject_CallFunctionObjArgs(reduce_frame_func, (PyObject *)frame, NULL); } +/* Helper function for gen_setstate and tb_setstate. + * It unwraps the first argument of the args tuple, if it is a _Frame_Wrapper. + * Returns a new reference to an argument tuple. + * + * This functionality is required, to adhere to the __reduce__/__setstate__ protocol. + * It requires, that __setstate__ accepts the state returned by __reduce__. (copy.copy() + * depends on it.) + */ +static PyObject * +unwrap_frame_arg(PyObject * args) { + PyObject *wrapper_type, *arg0, *result; + int is_instance; + Py_ssize_t len, i; + + if (!PyTuple_Check(args) || (len = PyTuple_Size(args)) < 1) { + if (len < 0) + return NULL; + Py_INCREF(args); + return args; + } + if ((arg0 = PyTuple_GetItem(args, 0)) == NULL) /* arg0 is a borrowed reference */ + return NULL; + if ((wrapper_type = PyObject_GetAttrString(reduce_frame_func, "__self__")) == NULL) + return NULL; + is_instance = PyObject_IsInstance(arg0, wrapper_type); + Py_DECREF(wrapper_type); + if (is_instance == 0) { + Py_INCREF(args); + return args; + } else if (is_instance == -1) { + return NULL; + } + if ((arg0 = PyObject_GetAttrString(arg0, "frame")) == NULL) + return NULL; + if ((result = PyTuple_New(len)) == NULL) { + Py_DECREF(arg0); + return NULL; + } + if (PyTuple_SetItem(result, 0, arg0)) { /* steals ref to arg0 */ + Py_DECREF(arg0); + Py_DECREF(result); + return NULL; + } + for (i=1; itb_next = next; @@ -2315,9 +2379,16 @@ gen_setstate(PyObject *self, PyObject *args) int gi_running; if (is_wrong_type(Py_TYPE(self))) return NULL; + + if ((args = unwrap_frame_arg(args)) == NULL) /* now args is a counted ref! */ + return NULL; + if (!PyArg_ParseTuple(args, "O!i:generator", - &PyFrame_Type, &f, &gi_running)) + &PyFrame_Type, &f, &gi_running)) { + Py_DECREF(args); return NULL; + } + Py_DECREF(args); if (!gi_running) { if ((f = slp_ensure_new_frame(f)) != NULL) {