cPickle can load pickles using proto 2 EXT[124] now, but can't yet

generate these opcodes.
This commit is contained in:
Tim Peters 2003-02-04 05:06:17 +00:00
parent d4b920c8bd
commit 2d62965734
2 changed files with 109 additions and 1 deletions

View File

@ -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

View File

@ -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;