Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 8a2d22a

Browse files
author
Anselm Kruis
committed
Issue #107: fix the __reduce__/__setstate__ protocol for generator and traceback objects
__setstate__ must accept the state returned by __reduce__. This was not the case for generator and trace-back objects. This commit fixes this. The next commit (merge of issue #127) adds the relevant test cases. Additionally amends changelog.txt. https://bitbucket.org/stackless-dev/stackless/issues/107
1 parent 131beaf commit 8a2d22a

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

Stackless/changelog.txt

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ What's New in Stackless 3.X.X?
7474
- https://bitbucket.org/stackless-dev/stackless/issues/107
7575
Improve unpickling of traceback objects. Stackless now reconstructs the
7676
frame.f_back linkage in frames directly referenced by traceback objects.
77+
Stackless no longer pretends to be able to pickle arbitrary frame objects.
7778

7879
- https://bitbucket.org/stackless-dev/stackless/issues/110
7980
Remove the already non functional remains of psyco support.

Stackless/pickling/prickelpit.c

+73-2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,64 @@ slp_reduce_frame(PyFrameObject * frame) {
209209
return PyObject_CallFunctionObjArgs(reduce_frame_func, (PyObject *)frame, NULL);
210210
}
211211

212+
/* Helper function for gen_setstate and tb_setstate.
213+
* It unwraps the first argument of the args tuple, if it is a _Frame_Wrapper.
214+
* Returns a new reference to an argument tuple.
215+
*
216+
* This functionality is required, to adhere to the __reduce__/__setstate__ protocol.
217+
* It requires, that __setstate__ accepts the state returned by __reduce__. (copy.copy()
218+
* depends on it.)
219+
*/
220+
static PyObject *
221+
unwrap_frame_arg(PyObject * args) {
222+
PyObject *wrapper_type, *arg0, *result;
223+
int is_instance;
224+
Py_ssize_t len, i;
225+
226+
if (!PyTuple_Check(args) || (len = PyTuple_Size(args)) < 1) {
227+
if (len < 0)
228+
return NULL;
229+
Py_INCREF(args);
230+
return args;
231+
}
232+
if ((arg0 = PyTuple_GetItem(args, 0)) == NULL) /* arg0 is a borrowed reference */
233+
return NULL;
234+
if ((wrapper_type = PyObject_GetAttrString(reduce_frame_func, "__self__")) == NULL)
235+
return NULL;
236+
is_instance = PyObject_IsInstance(arg0, wrapper_type);
237+
Py_DECREF(wrapper_type);
238+
if (is_instance == 0) {
239+
Py_INCREF(args);
240+
return args;
241+
} else if (is_instance == -1) {
242+
return NULL;
243+
}
244+
if ((arg0 = PyObject_GetAttrString(arg0, "frame")) == NULL)
245+
return NULL;
246+
if ((result = PyTuple_New(len)) == NULL) {
247+
Py_DECREF(arg0);
248+
return NULL;
249+
}
250+
if (PyTuple_SetItem(result, 0, arg0)) { /* steals ref to arg0 */
251+
Py_DECREF(arg0);
252+
Py_DECREF(result);
253+
return NULL;
254+
}
255+
for (i=1; i<len; i++) {
256+
if ((arg0 = PyTuple_GetItem(args, i)) == NULL) {
257+
Py_DECREF(result);
258+
return NULL;
259+
}
260+
/* arg0 is a borrowed reference */
261+
Py_INCREF(arg0);
262+
if (PyTuple_SetItem(result, i, arg0)) { /* steals ref to arg0 */
263+
Py_DECREF(arg0);
264+
Py_DECREF(result);
265+
return NULL;
266+
}
267+
}
268+
return result;
269+
}
212270

213271
static struct PyMethodDef _new_methoddef[] = {
214272
{"__new__", (PyCFunction)_new_wrapper, METH_VARARGS | METH_KEYWORDS,
@@ -1230,11 +1288,17 @@ tb_setstate(PyObject *self, PyObject *args)
12301288

12311289
if (is_wrong_type(Py_TYPE(tb))) return NULL;
12321290

1291+
if ((args = unwrap_frame_arg(args)) == NULL) /* now args is a counted ref! */
1292+
return NULL;
1293+
12331294
if (!PyArg_ParseTuple(args,
12341295
"O!ii|O!:traceback",
12351296
&PyFrame_Type, &frame,
1236-
&lasti, &lineno,&PyTraceBack_Type, &next))
1297+
&lasti, &lineno,&PyTraceBack_Type, &next)) {
1298+
Py_DECREF(args);
12371299
return NULL;
1300+
}
1301+
Py_DECREF(args);
12381302

12391303
Py_XINCREF(next);
12401304
tb->tb_next = next;
@@ -2315,9 +2379,16 @@ gen_setstate(PyObject *self, PyObject *args)
23152379
int gi_running;
23162380

23172381
if (is_wrong_type(Py_TYPE(self))) return NULL;
2382+
2383+
if ((args = unwrap_frame_arg(args)) == NULL) /* now args is a counted ref! */
2384+
return NULL;
2385+
23182386
if (!PyArg_ParseTuple(args, "O!i:generator",
2319-
&PyFrame_Type, &f, &gi_running))
2387+
&PyFrame_Type, &f, &gi_running)) {
2388+
Py_DECREF(args);
23202389
return NULL;
2390+
}
2391+
Py_DECREF(args);
23212392

23222393
if (!gi_running) {
23232394
if ((f = slp_ensure_new_frame(f)) != NULL) {

0 commit comments

Comments
 (0)