diff options
-rw-r--r-- | Lib/copy_reg.py | 2 | ||||
-rw-r--r-- | Modules/cPickle.c | 108 |
2 files changed, 109 insertions, 1 deletions
diff --git a/Lib/copy_reg.py b/Lib/copy_reg.py index e35d95e..c9c34c3 100644 --- a/Lib/copy_reg.py +++ b/Lib/copy_reg.py @@ -87,7 +87,7 @@ _extension_cache = {} # code -> object def add_extension(module, name, code): """Register an extension code.""" code = int(code) - if not 1 <= code < 0x7fffffff: + if not 1 <= code <= 0x7fffffff: raise ValueError, "code out of range" key = (module, name) if (_extension_registry.get(key) == code and diff --git a/Modules/cPickle.c b/Modules/cPickle.c index f5aadd2..a3a07b2 100644 --- a/Modules/cPickle.c +++ b/Modules/cPickle.c @@ -3733,6 +3733,74 @@ load_long_binget(Unpicklerobject *self) return rc; } +/* Push an object from the extension registry (EXT[124]). nbytes is + * the number of bytes following the opcode, holding the index (code) value. + */ +static int +load_extension(Unpicklerobject *self, int nbytes) +{ + char *codebytes; /* the nbytes bytes after the opcode */ + long code; /* calc_binint returns long */ + PyObject *py_code; /* code as a Python int */ + PyObject *obj; /* the object to push */ + PyObject *pair; /* (module_name, class_name) */ + PyObject *module_name, *class_name; + + assert(nbytes == 1 || nbytes == 2 || nbytes == 4); + if (self->read_func(self, &codebytes, nbytes) < 0) return -1; + code = calc_binint(codebytes, nbytes); + if (code <= 0) { /* note that 0 is forbidden */ + /* Corrupt or hostile pickle. */ + PyErr_SetString(UnpicklingError, "EXT specifies code <= 0"); + return -1; + } + + /* Look for the code in the cache. */ + py_code = PyInt_FromLong(code); + if (py_code == NULL) return -1; + obj = PyDict_GetItem(extension_cache, py_code); + if (obj != NULL) { + /* Bingo. */ + Py_DECREF(py_code); + PDATA_APPEND(self->stack, obj, -1); + return 0; + } + + /* Look up the (module_name, class_name) pair. */ + pair = PyDict_GetItem(inverted_registry, py_code); + if (pair == NULL) { + Py_DECREF(py_code); + PyErr_Format(PyExc_ValueError, "unregistered extension " + "code %ld", code); + return -1; + } + /* Since the extension registry is manipulable via Python code, + * confirm that obj is really a 2-tuple of strings. + */ + if (!PyTuple_Check(pair) || PyTuple_Size(pair) != 2 || + !PyString_Check(module_name = PyTuple_GET_ITEM(pair, 0)) || + !PyString_Check(class_name = PyTuple_GET_ITEM(pair, 1))) { + Py_DECREF(py_code); + PyErr_Format(PyExc_ValueError, "_inverted_registry[%ld] " + "isn't a 2-tuple of strings", code); + return -1; + } + /* Load the object. */ + obj = find_class(module_name, class_name, self->find_class); + if (obj == NULL) { + Py_DECREF(py_code); + return -1; + } + /* Cache code -> obj. */ + code = PyDict_SetItem(extension_cache, py_code, obj); + Py_DECREF(py_code); + if (code < 0) { + Py_DECREF(obj); + return -1; + } + PDATA_PUSH(self->stack, obj, -1); + return 0; +} static int load_put(Unpicklerobject *self) @@ -4214,6 +4282,20 @@ load(Unpicklerobject *self) break; continue; + case EXT1: + if (load_extension(self, 1) < 0) + break; + continue; + + case EXT2: + if (load_extension(self, 2) < 0) + break; + continue; + + case EXT4: + if (load_extension(self, 4) < 0) + break; + continue; case MARK: if (load_mark(self) < 0) break; @@ -4370,6 +4452,17 @@ noload_build(Unpicklerobject *self) { return 0; } +static int +noload_extension(Unpicklerobject *self, int nbytes) +{ + char *codebytes; + + assert(nbytes == 1 || nbytes == 2 || nbytes == 4); + if (self->read_func(self, &codebytes, nbytes) < 0) return -1; + PDATA_APPEND(self->stack, Py_None, -1); + return 0; +} + static PyObject * noload(Unpicklerobject *self) @@ -4557,6 +4650,21 @@ noload(Unpicklerobject *self) break; continue; + case EXT1: + if (noload_extension(self, 1) < 0) + break; + continue; + + case EXT2: + if (noload_extension(self, 2) < 0) + break; + continue; + + case EXT4: + if (noload_extension(self, 4) < 0) + break; + continue; + case MARK: if (load_mark(self) < 0) break; |