diff options
author | Tim Peters <tim.peters@gmail.com> | 2003-02-15 03:01:11 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2003-02-15 03:01:11 (GMT) |
commit | 080c88b9126c13d14d2383bee345a41529f14130 (patch) | |
tree | d129410fc4d235b4563257d5c12c43c69c1b5cbb /Modules | |
parent | d2c684f79fc1361442b7849d5a2d05b04988616d (diff) | |
download | cpython-080c88b9126c13d14d2383bee345a41529f14130.zip cpython-080c88b9126c13d14d2383bee345a41529f14130.tar.gz cpython-080c88b9126c13d14d2383bee345a41529f14130.tar.bz2 |
cPickle.c, load_build(): Taught cPickle how to pick apart
the optional proto 2 slot state.
pickle.py, load_build(): CAUTION: Noted that cPickle's
load_build and pickle's load_build really don't do the same
things with the state, and didn't before this patch either.
cPickle never tries to do .update(), and has no backoff if
instance.__dict__ can't be retrieved. There are no tests
that can tell the difference, and part of what cPickle's
load_build() did looked accidental to me, so I don't know
what the true intent is here.
pickletester.py, test_pickle.py: Got rid of the hack for
exempting cPickle from running some of the proto 2 tests.
dictobject.c, PyDict_Next(): documented intended use.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/cPickle.c | 92 |
1 files changed, 71 insertions, 21 deletions
diff --git a/Modules/cPickle.c b/Modules/cPickle.c index f09e502..3f3d82f 100644 --- a/Modules/cPickle.c +++ b/Modules/cPickle.c @@ -4309,43 +4309,93 @@ load_setitems(Unpicklerobject *self) static int load_build(Unpicklerobject *self) { - PyObject *value = 0, *inst = 0, *instdict = 0, *d_key = 0, *d_value = 0, - *junk = 0, *__setstate__ = 0; - int i, r = 0; + PyObject *state, *inst, *slotstate; + PyObject *__setstate__; + PyObject *d_key, *d_value; + int i; + int res = -1; - if (self->stack->length < 2) return stackUnderflow(); - PDATA_POP(self->stack, value); - if (! value) return -1; - inst=self->stack->data[self->stack->length-1]; + /* Stack is ... instance, state. We want to leave instance at + * the stack top, possibly mutated via instance.__setstate__(state). + */ + if (self->stack->length < 2) + return stackUnderflow(); + PDATA_POP(self->stack, state); + if (state == NULL) + return -1; + inst = self->stack->data[self->stack->length - 1]; + + __setstate__ = PyObject_GetAttr(inst, __setstate___str); + if (__setstate__ != NULL) { + PyObject *junk = NULL; - if ((__setstate__ = PyObject_GetAttr(inst, __setstate___str))) { - ARG_TUP(self, value); + /* The explicit __setstate__ is responsible for everything. */ + ARG_TUP(self, state); if (self->arg) { junk = PyObject_Call(__setstate__, self->arg, NULL); FREE_ARG_TUP(self); } Py_DECREF(__setstate__); - if (! junk) return -1; + if (junk == NULL) + return -1; Py_DECREF(junk); return 0; } - PyErr_Clear(); - if ((instdict = PyObject_GetAttr(inst, __dict___str))) { + + /* A default __setstate__. First see whether state embeds a + * slot state dict too (a proto 2 addition). + */ + if (PyTuple_Check(state) && PyTuple_Size(state) == 2) { + PyObject *temp = state; + state = PyTuple_GET_ITEM(temp, 0); + slotstate = PyTuple_GET_ITEM(temp, 1); + Py_INCREF(state); + Py_INCREF(slotstate); + Py_DECREF(temp); + } + else + slotstate = NULL; + + /* Set inst.__dict__ from the state dict (if any). */ + if (state != Py_None) { + PyObject *dict; + if (! PyDict_Check(state)) { + PyErr_SetString(UnpicklingError, "state is not a " + "dictionary"); + goto finally; + } + dict = PyObject_GetAttr(inst, __dict___str); + if (dict == NULL) + goto finally; + i = 0; - while (PyDict_Next(value, &i, &d_key, &d_value)) { - if (PyObject_SetItem(instdict, d_key, d_value) < 0) { - r=-1; - break; - } + while (PyDict_Next(state, &i, &d_key, &d_value)) { + if (PyObject_SetItem(dict, d_key, d_value) < 0) + goto finally; } - Py_DECREF(instdict); + Py_DECREF(dict); } - else r=-1; - Py_XDECREF(value); + /* Also set instance attributes from the slotstate dict (if any). */ + if (slotstate != NULL) { + if (! PyDict_Check(slotstate)) { + PyErr_SetString(UnpicklingError, "slot state is not " + "a dictionary"); + goto finally; + } + i = 0; + while (PyDict_Next(slotstate, &i, &d_key, &d_value)) { + if (PyObject_SetAttr(inst, d_key, d_value) < 0) + goto finally; + } + } + res = 0; - return r; + finally: + Py_DECREF(state); + Py_XDECREF(slotstate); + return res; } |