#include "Python.h"
#include "structmember.h"
PyDoc_STRVAR(pickle_module_doc,
"Optimized C implementation for the Python pickle module.");
/* Bump this when new opcodes are added to the pickle protocol. */
enum {
HIGHEST_PROTOCOL = 3,
DEFAULT_PROTOCOL = 3
};
/* Pickle opcodes. These must be kept updated with pickle.py.
Extensive docs are in pickletools.py. */
enum opcode {
MARK = '(',
STOP = '.',
POP = '0',
POP_MARK = '1',
DUP = '2',
FLOAT = 'F',
INT = 'I',
BININT = 'J',
BININT1 = 'K',
LONG = 'L',
BININT2 = 'M',
NONE = 'N',
PERSID = 'P',
BINPERSID = 'Q',
REDUCE = 'R',
STRING = 'S',
BINSTRING = 'T',
SHORT_BINSTRING = 'U',
UNICODE = 'V',
BINUNICODE = 'X',
APPEND = 'a',
BUILD = 'b',
GLOBAL = 'c',
DICT = 'd',
EMPTY_DICT = '}',
APPENDS = 'e',
GET = 'g',
BINGET = 'h',
INST = 'i',
LONG_BINGET = 'j',
LIST = 'l',
EMPTY_LIST = ']',
OBJ = 'o',
PUT = 'p',
BINPUT = 'q',
LONG_BINPUT = 'r',
SETITEM = 's',
TUPLE = 't',
EMPTY_TUPLE = ')',
SETITEMS = 'u',
BINFLOAT = 'G',
/* Protocol 2. */
PROTO = '\x80',
NEWOBJ = '\x81',
EXT1 = '\x82',
EXT2 = '\x83',
EXT4 = '\x84',
TUPLE1 = '\x85',
TUPLE2 = '\x86',
TUPLE3 = '\x87',
NEWTRUE = '\x88',
NEWFALSE = '\x89',
LONG1 = '\x8a',
LONG4 = '\x8b',
/* Protocol 3 (Python 3.x) */
BINBYTES = 'B',
SHORT_BINBYTES = 'C'
};
/* These aren't opcodes -- they're ways to pickle bools before protocol 2
* so that unpicklers written before bools were introduced unpickle them
* as ints, but unpicklers after can recognize that bools were intended.
* Note that protocol 2 added direct ways to pickle bools.
*/
#undef TRUE
#define TRUE "I01\n"
#undef FALSE
#define FALSE "I00\n"
enum {
/* Keep in synch with pickle.Pickler._BATCHSIZE. This is how many elements
batch_list/dict() pumps out before doing APPENDS/SETITEMS. Nothing will
break if this gets out of synch with pickle.py, but it's unclear that would
help anything either. */
BATCHSIZE = 1000,
/* Nesting limit until Pickler, when running in "fast mode", starts
checking for self-referential data-structures. */
FAST_NESTING_LIMIT = 50,
/* Initial size of the write buffer of Pickler. */
WRITE_BUF_SIZE = 4096,
/* Maximum size of the write buffer of Pickler when pickling to a
stream. This is ignored for in-memory pickling. */
MAX_WRITE_BUF_SIZE = 64 * 1024,
/* Prefetch size when unpickling (disabled on unpeekable streams) */
PREFETCH = 8192 * 16
};
/* Exception classes for pickle. These should override the ones defined in
pickle.py, when the C-optimized Pickler and Unpickler are used. */
static PyObject *PickleError = NULL;
static PyObject *PicklingError = NULL;
static PyObject *UnpicklingError = NULL;
/* copyreg.dispatch_table, {type_object: pickling_function} */
static PyObject *dispatch_table = NULL;
/* For EXT[124] opcodes. */
/* copyreg._extension_registry, {(module_name, function_name): code} */
static PyObject *extension_registry = NULL;
/* copyreg._inverted_registry, {code: (module_name, function_name)} */
static PyObject *inverted_registry = NULL;
/* copyreg._extension_cache, {code: object} */
static PyObject *extension_cache = NULL;
/* _compat_pickle.NAME_MAPPING, {(oldmodule, oldname): (newmodule, newname)} */
static PyObject *name_mapping_2to3 = NULL;
/* _compat_pickle.IMPORT_MAPPING, {oldmodule: newmodule} */
static PyObject *import_mapping_2to3 = NULL;
/* Same, but with REVERSE_NAME_MAPPING / REVERSE_IMPORT_MAPPING */
static PyObject *name_mapping_3to2 = NULL;
static PyObject *import_mapping_3to2 = NULL;
/* XXX: Are these really nescessary? */
/* As the name says, an empty tuple. */
static PyObject *empty_tuple = NULL;
/* For looking up name pairs in copyreg._extension_registry. */
static PyObject *two_tuple = NULL;
static int
stack_underflow(void)
{
PyErr_SetString(UnpicklingError, "unpickling stack underflow");
return -1;
}
/* Internal data type used as the unpickling stack. */
typedef struct {
PyObject_VAR_HEAD
PyObject **data;
Py_ssize_t allocated; /* number of slots in data allocated */
} Pdata;
static void
Pdata_dealloc(Pdata *self)
{
Py_ssize_t i = Py_SIZE(self);
while (--i >= 0) {
Py_DECREF(self->data[i]);
}
PyMem_FREE(self->data);
PyObject_Del(self);
}
static PyTypeObject Pdata_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_pickle.Pdata", /*tp_name*/
sizeof(Pdata), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)Pdata_dealloc, /*tp_dealloc*/
};
static PyObject *
Pdata_New(void)
{
Pdata *self;
if (!(self = PyObject_New(Pdata, &Pdata_Type)))
return NULL;
Py_SIZE(self) = 0;
self->allocated = 8;
self->data = PyMem_MALLOC(self->allocated * sizeof(PyObject *));
if (self->data)
return (PyObject *)self;
Py_DECREF(self);
return PyErr_NoMemory();
}
/* Retain only the initial clearto items. If clearto >= the current
* number of items, this is a (non-erroneous) NOP.
*/
static int
Pdata_clear(Pdata *self, Py_ssize_t clearto)
{
Py_ssize_t i = Py_SIZE(self);
if (clearto < 0)
return stack_underflow();
if (clearto >= i)
return 0;
while (--i >= clearto) {
Py_CLEAR(self->data[i]);
}
Py_SIZE(self) = clearto;
return 0;
}
static int
Pdata_grow(Pdata *self)
{
PyObject **data = self->data;
Py_ssize_t allocated = self->allocated;
Py_ssize_t new_allocated;
new_allocated = (allocated >> 3) + 6;
/* check for integer overflow */
if (new_allocated > PY_SSIZE_T_MAX - allocated)
goto nomemory;
new_allocated += allocated;
if ((size_t)new_allocated > ((size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)))
goto nomemory;
data = PyMem_REALLOC(data, new_allocated * sizeof(PyObject *));
if (data == NULL)
goto nomemory;
self->data = data;
self->allocated = new_allocated;
return 0;
nomemory:
PyErr_NoMemory();
return -1;
}
/* D is a Pdata*. Pop the topmost element and store it into V, which
* must be an lvalue holding PyObject*. On stack underflow, UnpicklingError
* is raised and V is set to NULL.
*/
static PyObject *
Pdata_pop(Pdata *self)
{
if (Py_SIZE(self) == 0) {
PyErr_SetString(UnpicklingError, "bad pickle data");
return NULL;
}
return self->data[--Py_SIZE(self)];
}
#define PDATA_POP(D, V) do { (V) = Pdata_pop((D)); } while (0)
static int
Pdata_push(Pdata *self, PyObject *obj)
{
if (Py_SIZE(self) == self->allocated && Pdata_grow(self) < 0) {
return -1;
}
self->data[Py_SIZE(self)++] = obj;
return 0;
}
/* Push an object on stack, transferring its ownership to the stack. */
#define PDATA_PUSH(D, O, ER) do { \
if (Pdata_push((D), (O)) < 0) return (ER); } while(0)
/* Push an object on stack, adding a new reference to the object. */
#define PDATA_APPEND(D, O, ER) do { \
Py_INCREF((O)); \
if (Pdata_push((D), (O)) < 0) return (ER); } while(0)
static PyObject *
Pdata_poptuple(Pdata *self, Py_ssize_t start)
{
PyObject *tuple;
Py_ssize_t len, i, j;
len = Py_SIZE(self) - start;
tuple = PyTuple_New(len);
if (tuple == NULL)
return NULL;
for (i = start, j = 0; j < len; i++, j++)
PyTuple_SET_ITEM(tuple, j, self->data[i]);
Py_SIZE(self) = start;
return tuple;
}
static PyObject *
Pdata_poplist(Pdata *self, Py_ssize_t start)
{
PyObject *list;
Py_ssize_t len, i, j;
len = Py_SIZE(self) - start;
list = PyList_New(len);
if (list == NULL)
return NULL;
for (i = start, j = 0; j < len; i++, j++)
PyList_SET_ITEM(list, j, self->data[i]);
Py_SIZE(self) = start;
return list;
}
typedef struct {
PyObject *me_key;
Py_ssize_t me_value;
} PyMemoEntry;
typedef struct {
Py_ssize_t mt_mask;
Py_ssize_t mt_used;
Py_ssize_t mt_allocated;
PyMemoEntry *mt_table;
} PyMemoTable;
typedef struct PicklerObject {
PyObject_HEAD
PyMemoTable *memo; /* Memo table, keep track of the seen
objects to support self-referential objects
pickling. */
PyObject *pers_func; /* persistent_id() method, can be NULL */
PyObject *dispatch_table; /* private dispatch_table, can be NULL */
PyObject *arg;
PyObject *write; /* write() method of the output stream. */
PyObject *output_buffer; /* Write into a local bytearray buffer before
flushing to the stream. */
Py_ssize_t output_len; /* Length of output_buffer. */
Py_ssize_t max_output_len; /* Allocation size of output_buffer. */
int proto; /* Pickle protocol number, >= 0 */
int bin; /* Boolean, true if proto > 0 */
Py_ssize_t buf_size; /* Size of the current buffered pickle data */
int fast; /* Enable fast mode if set to a true value.
The fast mode disable the usage of memo,
therefore speeding the pickling process by
not generating superfluous PUT opcodes. It
should not be used if with self-referential
objects. */
int fast_nesting;
int fix_imports; /* Indicate whether Pickler should fix
the name of globals for Python 2.x. */
PyObject *fast_memo;
} PicklerObject;
typedef struct UnpicklerObject {
Loading ...