diff -r 5fd60fd3ce1f Modules/_pickle.c --- a/Modules/_pickle.c Wed Aug 15 15:12:48 2012 +0200 +++ b/Modules/_pickle.c Wed Aug 15 15:32:26 2012 +0200 @@ -108,38 +108,132 @@ /* 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; +typedef struct _picklestate { + PyObject *Unpickler_Type; + PyObject *UnpicklerMemoProxyType; + PyObject *Pickler_Type; + PyObject *PicklerMemoProxyType; + PyObject *Pdata_Type; + PyObject *PickleError; /*NULL;*/ + PyObject *PicklingError; /*NULL;*/ + PyObject *UnpicklingError; /*NULL;*/ + /* copyreg.dispatch_table, {type_object: pickling_function} */ + PyObject *dispatch_table; /*NULL;*/ + /* For EXT[124] opcodes. */ + /* copyreg._extension_registry, {(module_name, function_name): code} */ + PyObject *extension_registry; /*NULL;*/ + /* copyreg._inverted_registry, {code: (module_name, function_name)} */ + PyObject *inverted_registry; /*NULL;*/ + /* copyreg._extension_cache, {code: object} */ + PyObject *extension_cache; /*NULL;*/ + /* _compat_pickle.NAME_MAPPING, {(oldmodule, oldname): (newmodule, newname)} */ + PyObject *name_mapping_2to3; /*NULL;*/ + /* _compat_pickle.IMPORT_MAPPING, {oldmodule: newmodule} */ + PyObject *import_mapping_2to3; /*NULL;*/ + /* Same, but with REVERSE_NAME_MAPPING / REVERSE_IMPORT_MAPPING */ + PyObject *name_mapping_3to2; /*NULL;*/ + PyObject *import_mapping_3to2; /*NULL;*/ + /* XXX: Are these really nescessary? */ + /* As the name says, an empty tuple. */ + PyObject *empty_tuple; /*NULL;*/ + /* For looking up name pairs in copyreg._extension_registry. */ + PyObject *two_tuple; /*NULL;*/ + PyObject *module_str; /*NULL;*/ + PyObject *main_str; /*NULL;*/ + PyObject *codecs_encode; /*NULL;*/ + PyObject *latin1; /*NULL;*/ + PyObject *name_str; /*NULL;*/ + PyObject *str_class; + PyObject *newobj_str; /*NULL*/ + PyObject *reduce_str; /*NULL;*/ + PyObject *reduce_ex_str; /*NULL;*/ +} _picklestate; + + +#define _pickle_state(o) ((_picklestate *)PyModule_GetState(o)) + +static int +_pickle_clear(PyObject *m) +{ + _picklestate *s = _pickle_state(m); + Py_CLEAR(s->UnpicklerMemoProxyType); + Py_CLEAR(s->Unpickler_Type); + Py_CLEAR(s->Pickler_Type); + Py_CLEAR(s->PicklerMemoProxyType); + Py_CLEAR(s->Pdata_Type); + Py_CLEAR(s->PickleError); + Py_CLEAR(s->PicklingError); + Py_CLEAR(s->UnpicklingError); + Py_CLEAR(s->dispatch_table); + Py_CLEAR(s->extension_registry); + Py_CLEAR(s->inverted_registry); + Py_CLEAR(s->extension_cache); + Py_CLEAR(s->name_mapping_2to3); + Py_CLEAR(s->import_mapping_2to3); + Py_CLEAR(s->name_mapping_3to2); + Py_CLEAR(s->import_mapping_3to2); + Py_CLEAR(s->empty_tuple); + Py_CLEAR(s->two_tuple); + Py_CLEAR(s->module_str); + Py_CLEAR(s->main_str); + Py_CLEAR(s->codecs_encode); + Py_CLEAR(s->latin1); + Py_CLEAR(s->name_str); + Py_CLEAR(s->str_class); + Py_CLEAR(s->newobj_str); + Py_CLEAR(s->reduce_str); + Py_CLEAR(s->reduce_ex_str); + return 0; +} + +static int +_pickle_traverse(PyObject *m, visitproc visit, void *arg) +{ + _picklestate *s = _pickle_state(m); + Py_VISIT(s->UnpicklerMemoProxyType); + Py_VISIT(s->Unpickler_Type); + Py_VISIT(s->Pickler_Type); + Py_VISIT(s->PicklerMemoProxyType); + Py_VISIT(s->Pdata_Type); + Py_VISIT(s->PickleError); + Py_VISIT(s->PicklingError); + Py_VISIT(s->UnpicklingError); + Py_VISIT(s->dispatch_table); + Py_VISIT(s->extension_registry); + Py_VISIT(s->inverted_registry); + Py_VISIT(s->extension_cache); + Py_VISIT(s->name_mapping_2to3); + Py_VISIT(s->import_mapping_2to3); + Py_VISIT(s->name_mapping_3to2); + Py_VISIT(s->import_mapping_3to2); + Py_VISIT(s->empty_tuple); + Py_VISIT(s->two_tuple); + Py_VISIT(s->module_str); + Py_VISIT(s->main_str); + Py_VISIT(s->codecs_encode); + Py_VISIT(s->latin1); + Py_VISIT(s->name_str); + Py_VISIT(s->str_class); + Py_VISIT(s->newobj_str); + Py_VISIT(s->reduce_str); + Py_VISIT(s->reduce_ex_str); + return 0; +} + +static void +_pickle_free(void *m) +{ + _pickle_clear((PyObject *)m); +} + +static PyModuleDef _picklemodule; + +#define _picklestate_global ((_picklestate *)PyModule_GetState(PyState_FindModule(&_picklemodule))) static int stack_underflow(void) { - PyErr_SetString(UnpicklingError, "unpickling stack underflow"); + PyErr_SetString(_picklestate_global->UnpicklingError, "unpickling stack underflow"); return -1; } @@ -153,33 +247,44 @@ static void Pdata_dealloc(Pdata *self) { + PyTypeObject *type = Py_TYPE(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*/ + if((void *)type->tp_dealloc == (void *)Pdata_dealloc) { + Py_DECREF(type); + } +} + +static PyType_Slot Pdata_Type_slots[] = { + {Py_tp_dealloc, (destructor)Pdata_dealloc}, + {0, 0} }; +static PyType_Spec Pdata_Type_spec = { + "_pickle.Pdata", + sizeof(Pdata), + 0, + 0, + Pdata_Type_slots, +}; + + static PyObject * Pdata_New(void) { Pdata *self; - if (!(self = PyObject_New(Pdata, &Pdata_Type))) + if (!(self = PyObject_New(Pdata, (PyTypeObject *)_picklestate_global->Pdata_Type))) return NULL; Py_SIZE(self) = 0; self->allocated = 8; self->data = PyMem_MALLOC(self->allocated * sizeof(PyObject *)); if (self->data) + Py_INCREF(_picklestate_global->Pdata_Type); return (PyObject *)self; Py_DECREF(self); return PyErr_NoMemory(); @@ -241,7 +346,7 @@ Pdata_pop(Pdata *self) { if (Py_SIZE(self) == 0) { - PyErr_SetString(UnpicklingError, "bad pickle data"); + PyErr_SetString(_picklestate_global->UnpicklingError, "bad pickle data"); return NULL; } return self->data[--Py_SIZE(self)]; @@ -382,9 +487,6 @@ /* Forward declarations */ static int save(PicklerObject *, PyObject *, int); static int save_reduce(PicklerObject *, PyObject *, PyObject *); -static PyTypeObject Pickler_Type; -static PyTypeObject Unpickler_Type; - /************************************************************************* A custom hashtable mapping void* to longs. This is used by the pickler for @@ -760,7 +862,8 @@ { PicklerObject *self; - self = PyObject_GC_New(PicklerObject, &Pickler_Type); + self = PyObject_GC_New(PicklerObject, + (PyTypeObject *)_picklestate_global->Pickler_Type); if (self == NULL) return NULL; @@ -788,6 +891,7 @@ Py_DECREF(self); return NULL; } + Py_INCREF(_picklestate_global->Pickler_Type); return self; } @@ -917,7 +1021,7 @@ return -1; if (n == READ_WHOLE_LINE) - data = PyObject_Call(self->readline, empty_tuple, NULL); + data = PyObject_Call(self->readline, _picklestate_global->empty_tuple, NULL); else { PyObject *len = PyLong_FromSsize_t(n); if (len == NULL) @@ -1132,7 +1236,8 @@ { UnpicklerObject *self; - self = PyObject_GC_New(UnpicklerObject, &Unpickler_Type); + self = PyObject_GC_New(UnpicklerObject, + (PyTypeObject *)_picklestate_global->Unpickler_Type); if (self == NULL) return NULL; @@ -1150,6 +1255,8 @@ return NULL; } + Py_INCREF(_picklestate_global->Unpickler_Type); + self->arg = NULL; self->pers_func = NULL; self->input_buffer = NULL; @@ -1257,7 +1364,7 @@ len = 5; } else { /* unlikely */ - PyErr_SetString(PicklingError, + PyErr_SetString(_picklestate_global->PicklingError, "memo id too large for LONG_BINGET"); return -1; } @@ -1307,7 +1414,7 @@ len = 5; } else { /* unlikely */ - PyErr_SetString(PicklingError, + PyErr_SetString(_picklestate_global->PicklingError, "memo id too large for LONG_BINPUT"); return -1; } @@ -1328,23 +1435,23 @@ whichmodule(PyObject *global, PyObject *global_name) { Py_ssize_t i, j; - static PyObject *module_str = NULL; - static PyObject *main_str = NULL; + + PyObject *module_name; PyObject *modules_dict; PyObject *module; PyObject *obj; - if (module_str == NULL) { - module_str = PyUnicode_InternFromString("__module__"); - if (module_str == NULL) + if (_picklestate_global->module_str == NULL) { + _picklestate_global->module_str = PyUnicode_InternFromString("__module__"); + if (_picklestate_global->module_str == NULL) return NULL; - main_str = PyUnicode_InternFromString("__main__"); - if (main_str == NULL) + _picklestate_global->main_str = PyUnicode_InternFromString("__main__"); + if (_picklestate_global->main_str == NULL) return NULL; } - module_name = PyObject_GetAttr(global, module_str); + module_name = PyObject_GetAttr(global, _picklestate_global->module_str); /* In some rare cases (e.g., bound methods of extension types), __module__ can be None. If it is so, then search sys.modules @@ -1370,7 +1477,7 @@ i = 0; module_name = NULL; while ((j = PyDict_Next(modules_dict, &i, &module_name, &module))) { - if (PyObject_RichCompareBool(module_name, main_str, Py_EQ) == 1) + if (PyObject_RichCompareBool(module_name, _picklestate_global->main_str, Py_EQ) == 1) continue; obj = PyObject_GetAttr(module, global_name); @@ -1393,7 +1500,7 @@ /* If no module is found, use __main__. */ if (!j) { - module_name = main_str; + module_name = _picklestate_global->main_str; } Py_INCREF(module_name); @@ -1719,18 +1826,18 @@ Python 2 *and* the appropriate 'bytes' object when unpickled using Python 3. Again this is a hack and we don't need to do this with newer protocols. */ - static PyObject *codecs_encode = NULL; + PyObject *reduce_value = NULL; int status; - if (codecs_encode == NULL) { + if (_picklestate_global->codecs_encode == NULL) { PyObject *codecs_module = PyImport_ImportModule("codecs"); if (codecs_module == NULL) { return -1; } - codecs_encode = PyObject_GetAttrString(codecs_module, "encode"); + _picklestate_global->codecs_encode = PyObject_GetAttrString(codecs_module, "encode"); Py_DECREF(codecs_module); - if (codecs_encode == NULL) { + if (_picklestate_global->codecs_encode == NULL) { return -1; } } @@ -1739,20 +1846,22 @@ reduce_value = Py_BuildValue("(O())", (PyObject*)&PyBytes_Type); } else { - static PyObject *latin1 = NULL; + PyObject *unicode_str = PyUnicode_DecodeLatin1(PyBytes_AS_STRING(obj), PyBytes_GET_SIZE(obj), "strict"); if (unicode_str == NULL) return -1; - if (latin1 == NULL) { - latin1 = PyUnicode_InternFromString("latin1"); - if (latin1 == NULL) + if (_picklestate_global->latin1 == NULL) { + _picklestate_global->latin1 = PyUnicode_InternFromString("latin1"); + if (_picklestate_global->latin1 == NULL) return -1; } reduce_value = Py_BuildValue("(O(OO))", - codecs_encode, unicode_str, latin1); + _picklestate_global->codecs_encode, + unicode_str, + _picklestate_global->latin1); Py_DECREF(unicode_str); } @@ -2559,7 +2668,7 @@ static int save_global(PicklerObject *self, PyObject *obj, PyObject *name) { - static PyObject *name_str = NULL; + PyObject *global_name = NULL; PyObject *module_name = NULL; PyObject *module = NULL; @@ -2568,9 +2677,9 @@ const char global_op = GLOBAL; - if (name_str == NULL) { - name_str = PyUnicode_InternFromString("__name__"); - if (name_str == NULL) + if (_picklestate_global->name_str == NULL) { + _picklestate_global->name_str = PyUnicode_InternFromString("__name__"); + if (_picklestate_global->name_str == NULL) goto error; } @@ -2579,7 +2688,7 @@ Py_INCREF(global_name); } else { - global_name = PyObject_GetAttr(obj, name_str); + global_name = PyObject_GetAttr(obj, _picklestate_global->name_str); if (global_name == NULL) goto error; } @@ -2598,21 +2707,21 @@ extra parameters of __import__ to fix that. */ module = PyImport_Import(module_name); if (module == NULL) { - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "Can't pickle %R: import of module %R failed", obj, module_name); goto error; } cls = PyObject_GetAttr(module, global_name); if (cls == NULL) { - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "Can't pickle %R: attribute lookup %S.%S failed", obj, module_name, global_name); goto error; } if (cls != obj) { Py_DECREF(cls); - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "Can't pickle %R: it's not the same object as %S.%S", obj, module_name, global_name); goto error; @@ -2628,9 +2737,11 @@ char pdata[5]; Py_ssize_t n; - PyTuple_SET_ITEM(two_tuple, 0, module_name); - PyTuple_SET_ITEM(two_tuple, 1, global_name); - code_obj = PyDict_GetItem(extension_registry, two_tuple); + PyTuple_SET_ITEM(_picklestate_global->two_tuple, 0, module_name); + PyTuple_SET_ITEM(_picklestate_global->two_tuple, 1, global_name); + code_obj = PyDict_GetItem(_picklestate_global->extension_registry, _picklestate_global->two_tuple); + PyTuple_SET_ITEM(_picklestate_global->two_tuple, 0, NULL); + PyTuple_SET_ITEM(_picklestate_global->two_tuple, 1, NULL); /* The object is not registered in the extension registry. This is the most likely code path. */ if (code_obj == NULL) @@ -2642,7 +2753,7 @@ /* Verify code_obj has the right type and value. */ if (!PyLong_Check(code_obj)) { - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "Can't pickle %R: extension code %R isn't an integer", obj, code_obj); goto error; @@ -2650,7 +2761,7 @@ code = PyLong_AS_LONG(code_obj); if (code <= 0 || code > 0x7fffffffL) { if (!PyErr_Occurred()) - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "Can't pickle %R: extension code %ld is out of range", obj, code); goto error; @@ -2711,7 +2822,7 @@ key = PyTuple_Pack(2, module_name, global_name); if (key == NULL) goto error; - item = PyDict_GetItemWithError(name_mapping_3to2, key); + item = PyDict_GetItemWithError(_picklestate_global->name_mapping_3to2, key); Py_DECREF(key); if (item) { if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2) { @@ -2741,7 +2852,7 @@ goto error; } - item = PyDict_GetItemWithError(import_mapping_3to2, module_name); + item = PyDict_GetItemWithError(_picklestate_global->import_mapping_3to2, module_name); if (item) { if (!PyUnicode_Check(item)) { PyErr_Format(PyExc_RuntimeError, @@ -2763,7 +2874,7 @@ encoded = unicode_encoder(module_name); if (encoded == NULL) { if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "can't pickle module identifier '%S' using " "pickle protocol %i", module_name, self->proto); goto error; @@ -2781,7 +2892,7 @@ encoded = unicode_encoder(global_name); if (encoded == NULL) { if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "can't pickle global identifier '%S' using " "pickle protocol %i", global_name, self->proto); goto error; @@ -2893,14 +3004,13 @@ get_class(PyObject *obj) { PyObject *cls; - static PyObject *str_class; - - if (str_class == NULL) { - str_class = PyUnicode_InternFromString("__class__"); - if (str_class == NULL) + + if (_picklestate_global->str_class == NULL) { + _picklestate_global->str_class = PyUnicode_InternFromString("__class__"); + if (_picklestate_global->str_class == NULL) return NULL; } - cls = PyObject_GetAttr(obj, str_class); + cls = PyObject_GetAttr(obj, _picklestate_global->str_class); if (cls == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); @@ -2932,7 +3042,7 @@ size = PyTuple_Size(args); if (size < 2 || size > 5) { - PyErr_SetString(PicklingError, "tuple returned by " + PyErr_SetString(_picklestate_global->PicklingError, "tuple returned by " "__reduce__ must contain 2 through 5 elements"); return -1; } @@ -2942,12 +3052,12 @@ return -1; if (!PyCallable_Check(callable)) { - PyErr_SetString(PicklingError, "first item of the tuple " + PyErr_SetString(_picklestate_global->PicklingError, "first item of the tuple " "returned by __reduce__ must be callable"); return -1; } if (!PyTuple_Check(argtup)) { - PyErr_SetString(PicklingError, "second item of the tuple " + PyErr_SetString(_picklestate_global->PicklingError, "second item of the tuple " "returned by __reduce__ must be a tuple"); return -1; } @@ -2958,7 +3068,7 @@ if (listitems == Py_None) listitems = NULL; else if (!PyIter_Check(listitems)) { - PyErr_Format(PicklingError, "Fourth element of tuple" + PyErr_Format(_picklestate_global->PicklingError, "Fourth element of tuple" "returned by __reduce__ must be an iterator, not %s", Py_TYPE(listitems)->tp_name); return -1; @@ -2967,7 +3077,7 @@ if (dictitems == Py_None) dictitems = NULL; else if (!PyIter_Check(dictitems)) { - PyErr_Format(PicklingError, "Fifth element of tuple" + PyErr_Format(_picklestate_global->PicklingError, "Fifth element of tuple" "returned by __reduce__ must be an iterator, not %s", Py_TYPE(dictitems)->tp_name); return -1; @@ -2976,17 +3086,17 @@ /* Protocol 2 special case: if callable's name is __newobj__, use NEWOBJ. */ if (use_newobj) { - static PyObject *newobj_str = NULL, *name_str = NULL; + PyObject *name; - if (newobj_str == NULL) { - newobj_str = PyUnicode_InternFromString("__newobj__"); - name_str = PyUnicode_InternFromString("__name__"); - if (newobj_str == NULL || name_str == NULL) + if (_picklestate_global->newobj_str == NULL) { + _picklestate_global->newobj_str = PyUnicode_InternFromString("__newobj__"); + _picklestate_global->name_str = PyUnicode_InternFromString("__name__"); + if (_picklestate_global->newobj_str == NULL || _picklestate_global->name_str == NULL) return -1; } - name = PyObject_GetAttr(callable, name_str); + name = PyObject_GetAttr(callable, _picklestate_global->name_str); if (name == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_Clear(); @@ -2996,7 +3106,7 @@ } else { use_newobj = PyUnicode_Check(name) && - PyUnicode_Compare(name, newobj_str) == 0; + PyUnicode_Compare(name, _picklestate_global->newobj_str) == 0; Py_DECREF(name); } } @@ -3008,13 +3118,13 @@ /* Sanity checks. */ if (Py_SIZE(argtup) < 1) { - PyErr_SetString(PicklingError, "__newobj__ arglist is empty"); + PyErr_SetString(_picklestate_global->PicklingError, "__newobj__ arglist is empty"); return -1; } cls = PyTuple_GET_ITEM(argtup, 0); if (!PyType_Check(cls)) { - PyErr_SetString(PicklingError, "args[0] from " + PyErr_SetString(_picklestate_global->PicklingError, "args[0] from " "__newobj__ args is not a type"); return -1; } @@ -3024,7 +3134,7 @@ p = obj_class != cls; /* true iff a problem */ Py_DECREF(obj_class); if (p) { - PyErr_SetString(PicklingError, "args[0] from " + PyErr_SetString(_picklestate_global->PicklingError, "args[0] from " "__newobj__ args has the wrong class"); return -1; } @@ -3194,7 +3304,7 @@ } else if (type == &PyFunction_Type) { status = save_global(self, obj, NULL); - if (status < 0 && PyErr_ExceptionMatches(PickleError)) { + if (status < 0 && PyErr_ExceptionMatches(_picklestate_global->PickleError)) { /* fall back to reduce */ PyErr_Clear(); } @@ -3214,7 +3324,7 @@ * __reduce_ex__ method, or the object's __reduce__ method. */ if (self->dispatch_table == NULL) { - reduce_func = PyDict_GetItem(dispatch_table, (PyObject *)type); + reduce_func = PyDict_GetItem(_picklestate_global->dispatch_table, (PyObject *)type); /* PyDict_GetItem() unlike PyObject_GetItem() and PyObject_GetAttr() returns a borrowed ref */ Py_XINCREF(reduce_func); @@ -3236,16 +3346,16 @@ goto done; } else { - static PyObject *reduce_str = NULL; - static PyObject *reduce_ex_str = NULL; + + /* Cache the name of the reduce methods. */ - if (reduce_str == NULL) { - reduce_str = PyUnicode_InternFromString("__reduce__"); - if (reduce_str == NULL) + if (_picklestate_global->reduce_str == NULL) { + _picklestate_global->reduce_str = PyUnicode_InternFromString("__reduce__"); + if (_picklestate_global->reduce_str == NULL) goto error; - reduce_ex_str = PyUnicode_InternFromString("__reduce_ex__"); - if (reduce_ex_str == NULL) + _picklestate_global->reduce_ex_str = PyUnicode_InternFromString("__reduce_ex__"); + if (_picklestate_global->reduce_ex_str == NULL) goto error; } @@ -3258,7 +3368,7 @@ don't actually have to check for a __reduce__ method. */ /* Check for a __reduce_ex__ method. */ - reduce_func = PyObject_GetAttr(obj, reduce_ex_str); + reduce_func = PyObject_GetAttr(obj, _picklestate_global->reduce_ex_str); if (reduce_func != NULL) { PyObject *proto; proto = PyLong_FromLong(self->proto); @@ -3272,12 +3382,12 @@ else goto error; /* Check for a __reduce__ method. */ - reduce_func = PyObject_GetAttr(obj, reduce_str); + reduce_func = PyObject_GetAttr(obj, _picklestate_global->reduce_str); if (reduce_func != NULL) { - reduce_value = PyObject_Call(reduce_func, empty_tuple, NULL); + reduce_value = PyObject_Call(reduce_func, _picklestate_global->empty_tuple, NULL); } else { - PyErr_Format(PicklingError, "can't pickle '%.200s' object: %R", + PyErr_Format(_picklestate_global->PicklingError, "can't pickle '%.200s' object: %R", type->tp_name, obj); goto error; } @@ -3293,7 +3403,7 @@ } if (!PyTuple_Check(reduce_value)) { - PyErr_SetString(PicklingError, + PyErr_SetString(_picklestate_global->PicklingError, "__reduce__ must return a string or tuple"); goto error; } @@ -3363,7 +3473,7 @@ Developers often forget to call __init__() in their subclasses, which would trigger a segfault without this check. */ if (self->write == NULL) { - PyErr_Format(PicklingError, + PyErr_Format(_picklestate_global->PicklingError, "Pickler.__init__() was not called by %s.__init__()", Py_TYPE(self)->tp_name); return NULL; @@ -3395,6 +3505,7 @@ static void Pickler_dealloc(PicklerObject *self) { + PyTypeObject *type = Py_TYPE(self); PyObject_GC_UnTrack(self); Py_XDECREF(self->output_buffer); @@ -3406,7 +3517,10 @@ PyMemoTable_Del(self->memo); - Py_TYPE(self)->tp_free((PyObject *)self); + type->tp_free((PyObject *)self); + if((void *)type->tp_dealloc == (void *)Pickler_dealloc) { + Py_DECREF(type); + } } static int @@ -3470,6 +3584,7 @@ PyObject *file; PyObject *proto_obj = NULL; PyObject *fix_imports = Py_True; + PyObject *dispatch_table = _picklestate_global->dispatch_table; _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -3629,9 +3744,13 @@ static void PicklerMemoProxy_dealloc(PicklerMemoProxyObject *self) { + PyTypeObject *type = Py_TYPE(self); PyObject_GC_UnTrack(self); Py_XDECREF(self->pickler); PyObject_GC_Del((PyObject *)self); + if((void *)type->tp_dealloc == (void *)PicklerMemoProxy_dealloc) { + Py_DECREF(type); + } } static int @@ -3649,45 +3768,37 @@ return 0; } -static PyTypeObject PicklerMemoProxyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.PicklerMemoProxy", /*tp_name*/ - sizeof(PicklerMemoProxyObject), /*tp_basicsize*/ +static PyType_Slot PicklerMemoProxyType_slots[] = { + {Py_tp_dealloc, (destructor)PicklerMemoProxy_dealloc}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_setattro, PyObject_GenericSetAttr}, + {Py_tp_traverse, (traverseproc)PicklerMemoProxy_traverse}, + {Py_tp_clear, (inquiry)PicklerMemoProxy_clear}, + {Py_tp_methods, picklerproxy_methods}, + {Py_tp_members, }, + {0, 0} +}; + +static PyType_Spec PicklerMemoProxyType_spec = { + "_pickle.PicklerMemoProxy", + sizeof(PicklerMemoProxyObject), 0, - (destructor)PicklerMemoProxy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - 0, /* tp_doc */ - (traverseproc)PicklerMemoProxy_traverse, /* tp_traverse */ - (inquiry)PicklerMemoProxy_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - picklerproxy_methods, /* tp_methods */ + PicklerMemoProxyType_slots, }; + static PyObject * PicklerMemoProxy_New(PicklerObject *pickler) { PicklerMemoProxyObject *self; - self = PyObject_GC_New(PicklerMemoProxyObject, &PicklerMemoProxyType); + self = PyObject_GC_New(PicklerMemoProxyObject, + (PyTypeObject *)_picklestate_global->PicklerMemoProxyType); if (self == NULL) return NULL; + Py_INCREF(_picklestate_global->PicklerMemoProxyType); Py_INCREF(pickler); self->pickler = pickler; PyObject_GC_Track(self); @@ -3713,7 +3824,7 @@ return -1; } - if (Py_TYPE(obj) == &PicklerMemoProxyType) { + if (Py_TYPE(obj) == (PyTypeObject *)_picklestate_global->PicklerMemoProxyType) { PicklerObject *pickler = ((PicklerMemoProxyObject *)obj)->pickler; @@ -3813,49 +3924,31 @@ {NULL} }; -static PyTypeObject Pickler_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.Pickler" , /*tp_name*/ - sizeof(PicklerObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Pickler_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ +static PyType_Slot Pickler_Type_slots[] = { + {Py_tp_dealloc, (destructor)Pickler_dealloc}, + {Py_tp_doc, Pickler_doc}, + {Py_tp_traverse, (traverseproc)Pickler_traverse}, + {Py_tp_clear, (inquiry)Pickler_clear}, + {Py_tp_methods, Pickler_methods}, + {Py_tp_members, Pickler_members}, + {Py_tp_getset, Pickler_getsets}, + {Py_tp_init, (initproc)Pickler_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, PyType_GenericNew}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_bases, }, + {0, 0} +}; + +static PyType_Spec Pickler_Type_spec = { + "_pickle.Pickler", + sizeof(PicklerObject), + 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - Pickler_doc, /*tp_doc*/ - (traverseproc)Pickler_traverse, /*tp_traverse*/ - (inquiry)Pickler_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - Pickler_methods, /*tp_methods*/ - Pickler_members, /*tp_members*/ - Pickler_getsets, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - (initproc)Pickler_init, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - PyType_GenericNew, /*tp_new*/ - PyObject_GC_Del, /*tp_free*/ - 0, /*tp_is_gc*/ + Pickler_Type_slots, }; + /* Temporary helper for calling self.find_class(). XXX: It would be nice to able to avoid Python function call overhead, by @@ -3876,7 +3969,7 @@ marker(UnpicklerObject *self) { if (self->num_marks < 1) { - PyErr_SetString(UnpicklingError, "could not find MARK"); + PyErr_SetString(_picklestate_global->UnpicklingError, "could not find MARK"); return -1; } @@ -3893,7 +3986,7 @@ static int bad_readline(void) { - PyErr_SetString(UnpicklingError, "pickle data was truncated"); + PyErr_SetString(_picklestate_global->UnpicklingError, "pickle data was truncated"); return -1; } @@ -4091,7 +4184,7 @@ size = calc_binint(nbytes, size); if (size < 0) { /* Corrupt or hostile pickle -- we never write one like this */ - PyErr_SetString(UnpicklingError, + PyErr_SetString(_picklestate_global->UnpicklingError, "LONG pickle has negative byte count"); return -1; } @@ -4276,7 +4369,7 @@ x = calc_binint(s, 4); if (x < 0) { - PyErr_SetString(UnpicklingError, + PyErr_SetString(_picklestate_global->UnpicklingError, "BINSTRING pickle has negative byte count"); return -1; } @@ -4584,7 +4677,7 @@ if (args == NULL) goto error; if (!PyTuple_Check(args)) { - PyErr_SetString(UnpicklingError, "NEWOBJ expected an arg " "tuple."); + PyErr_SetString(_picklestate_global->UnpicklingError, "NEWOBJ expected an arg " "tuple."); goto error; } @@ -4593,12 +4686,12 @@ if (cls == NULL) goto error; if (!PyType_Check(cls)) { - PyErr_SetString(UnpicklingError, "NEWOBJ class argument " + PyErr_SetString(_picklestate_global->UnpicklingError, "NEWOBJ class argument " "isn't a type object"); goto error; } if (cls->tp_new == NULL) { - PyErr_SetString(UnpicklingError, "NEWOBJ class argument " + PyErr_SetString(_picklestate_global->UnpicklingError, "NEWOBJ class argument " "has NULL tp_new"); goto error; } @@ -4682,7 +4775,7 @@ return 0; } else { - PyErr_SetString(UnpicklingError, + PyErr_SetString(_picklestate_global->UnpicklingError, "A load persistent id instruction was encountered,\n" "but no persistent_load function was specified."); return -1; @@ -4709,7 +4802,7 @@ return 0; } else { - PyErr_SetString(UnpicklingError, + PyErr_SetString(_picklestate_global->UnpicklingError, "A load persistent id instruction was encountered,\n" "but no persistent_load function was specified."); return -1; @@ -4870,7 +4963,7 @@ code = calc_binint(codebytes, nbytes); if (code <= 0) { /* note that 0 is forbidden */ /* Corrupt or hostile pickle. */ - PyErr_SetString(UnpicklingError, "EXT specifies code <= 0"); + PyErr_SetString(_picklestate_global->UnpicklingError, "EXT specifies code <= 0"); return -1; } @@ -4878,7 +4971,7 @@ py_code = PyLong_FromLong(code); if (py_code == NULL) return -1; - obj = PyDict_GetItem(extension_cache, py_code); + obj = PyDict_GetItem(_picklestate_global->extension_cache, py_code); if (obj != NULL) { /* Bingo. */ Py_DECREF(py_code); @@ -4887,7 +4980,7 @@ } /* Look up the (module_name, class_name) pair. */ - pair = PyDict_GetItem(inverted_registry, py_code); + pair = PyDict_GetItem(_picklestate_global->inverted_registry, py_code); if (pair == NULL) { Py_DECREF(py_code); PyErr_Format(PyExc_ValueError, "unregistered extension " @@ -4912,7 +5005,7 @@ return -1; } /* Cache code -> obj. */ - code = PyDict_SetItem(extension_cache, py_code, obj); + code = PyDict_SetItem(_picklestate_global->extension_cache, py_code, obj); Py_DECREF(py_code); if (code < 0) { Py_DECREF(obj); @@ -5076,7 +5169,7 @@ return 0; if ((len - x) % 2 != 0) { /* Currupt or hostile pickle -- we never write one like this. */ - PyErr_SetString(UnpicklingError, "odd number of items for SETITEMS"); + PyErr_SetString(_picklestate_global->UnpicklingError, "odd number of items for SETITEMS"); return -1; } @@ -5175,7 +5268,7 @@ _Py_IDENTIFIER(__dict__); if (!PyDict_Check(state)) { - PyErr_SetString(UnpicklingError, "state is not a dictionary"); + PyErr_SetString(_picklestate_global->UnpicklingError, "state is not a dictionary"); goto error; } dict = _PyObject_GetAttrId(inst, &PyId___dict__); @@ -5204,7 +5297,7 @@ Py_ssize_t i; if (!PyDict_Check(slotstate)) { - PyErr_SetString(UnpicklingError, + PyErr_SetString(_picklestate_global->UnpicklingError, "slot state is not a dictionary"); goto error; } @@ -5395,7 +5488,7 @@ if (s[0] == '\0') PyErr_SetNone(PyExc_EOFError); else - PyErr_Format(UnpicklingError, + PyErr_Format(_picklestate_global->UnpicklingError, "invalid load key, '%c'.", s[0]); return NULL; } @@ -5433,7 +5526,7 @@ not call Unpickler.__init__(). Here, we simply ensure that self->read is not NULL. */ if (self->read == NULL) { - PyErr_Format(UnpicklingError, + PyErr_Format(_picklestate_global->UnpicklingError, "Unpickler.__init__() was not called by %s.__init__()", Py_TYPE(self)->tp_name); return NULL; @@ -5480,7 +5573,7 @@ key = PyTuple_Pack(2, module_name, global_name); if (key == NULL) return NULL; - item = PyDict_GetItemWithError(name_mapping_2to3, key); + item = PyDict_GetItemWithError(_picklestate_global->name_mapping_2to3, key); Py_DECREF(key); if (item) { if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2) { @@ -5506,7 +5599,7 @@ } /* Check if the module was renamed. */ - item = PyDict_GetItemWithError(import_mapping_2to3, module_name); + item = PyDict_GetItemWithError(_picklestate_global->import_mapping_2to3, module_name); if (item) { if (!PyUnicode_Check(item)) { PyErr_Format(PyExc_RuntimeError, @@ -5552,6 +5645,7 @@ static void Unpickler_dealloc(UnpicklerObject *self) { + PyTypeObject *type = Py_TYPE(self); PyObject_GC_UnTrack((PyObject *)self); Py_XDECREF(self->readline); Py_XDECREF(self->read); @@ -5570,7 +5664,10 @@ free(self->encoding); free(self->errors); - Py_TYPE(self)->tp_free((PyObject *)self); + type->tp_free((PyObject *)self); + if((void *)type->tp_dealloc == (void *)Unpickler_dealloc) { + Py_DECREF(type); + } } static int @@ -5808,9 +5905,13 @@ static void UnpicklerMemoProxy_dealloc(UnpicklerMemoProxyObject *self) { + PyTypeObject *type = Py_TYPE(self); PyObject_GC_UnTrack(self); Py_XDECREF(self->unpickler); PyObject_GC_Del((PyObject *)self); + if((void *)type->tp_dealloc == (void *)UnpicklerMemoProxy_dealloc) { + Py_DECREF(type); + } } static int @@ -5828,46 +5929,37 @@ return 0; } -static PyTypeObject UnpicklerMemoProxyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.UnpicklerMemoProxy", /*tp_name*/ - sizeof(UnpicklerMemoProxyObject), /*tp_basicsize*/ +static PyType_Slot UnpicklerMemoProxyType_slots[] = { + {Py_tp_dealloc, (destructor)UnpicklerMemoProxy_dealloc}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_setattro, PyObject_GenericSetAttr}, + {Py_tp_traverse, (traverseproc)UnpicklerMemoProxy_traverse}, + {Py_tp_clear, (inquiry)UnpicklerMemoProxy_clear}, + {Py_tp_methods, unpicklerproxy_methods}, + {Py_tp_members, }, + {0, 0} +}; + +static PyType_Spec UnpicklerMemoProxyType_spec = { + "_pickle.UnpicklerMemoProxy", + sizeof(UnpicklerMemoProxyObject), 0, - (destructor)UnpicklerMemoProxy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - 0, /* tp_doc */ - (traverseproc)UnpicklerMemoProxy_traverse, /* tp_traverse */ - (inquiry)UnpicklerMemoProxy_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - unpicklerproxy_methods, /* tp_methods */ + UnpicklerMemoProxyType_slots, }; + static PyObject * UnpicklerMemoProxy_New(UnpicklerObject *unpickler) { UnpicklerMemoProxyObject *self; self = PyObject_GC_New(UnpicklerMemoProxyObject, - &UnpicklerMemoProxyType); + (PyTypeObject *)_picklestate_global->UnpicklerMemoProxyType); if (self == NULL) return NULL; + Py_INCREF(_picklestate_global->UnpicklerMemoProxyType); Py_INCREF(unpickler); self->unpickler = unpickler; PyObject_GC_Track(self); @@ -5896,7 +5988,7 @@ return -1; } - if (Py_TYPE(obj) == &UnpicklerMemoProxyType) { + if (Py_TYPE(obj) == (PyTypeObject *)_picklestate_global->UnpicklerMemoProxyType) { UnpicklerObject *unpickler = ((UnpicklerMemoProxyObject *)obj)->unpickler; @@ -5999,49 +6091,30 @@ {NULL} }; -static PyTypeObject Unpickler_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.Unpickler", /*tp_name*/ - sizeof(UnpicklerObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Unpickler_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ +static PyType_Slot Unpickler_Type_slots[] = { + {Py_tp_dealloc, (destructor)Unpickler_dealloc}, + {Py_tp_doc, Unpickler_doc}, + {Py_tp_traverse, (traverseproc)Unpickler_traverse}, + {Py_tp_clear, (inquiry)Unpickler_clear}, + {Py_tp_methods, Unpickler_methods}, + {Py_tp_getset, Unpickler_getsets}, + {Py_tp_init, (initproc)Unpickler_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, PyType_GenericNew}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_bases, }, + {0, 0} +}; + +static PyType_Spec Unpickler_Type_spec = { + "_pickle.Unpickler", + sizeof(UnpicklerObject), + 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - Unpickler_doc, /*tp_doc*/ - (traverseproc)Unpickler_traverse, /*tp_traverse*/ - (inquiry)Unpickler_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - Unpickler_methods, /*tp_methods*/ - 0, /*tp_members*/ - Unpickler_getsets, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - (initproc)Unpickler_init, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - PyType_GenericNew, /*tp_new*/ - PyObject_GC_Del, /*tp_free*/ - 0, /*tp_is_gc*/ + Unpickler_Type_slots, }; + PyDoc_STRVAR(pickle_dump_doc, "dump(obj, file, protocol=None, *, fix_imports=True) -> None\n" "\n" @@ -6329,18 +6402,18 @@ copyreg = PyImport_ImportModule("copyreg"); if (!copyreg) goto error; - dispatch_table = PyObject_GetAttrString(copyreg, "dispatch_table"); - if (!dispatch_table) + _picklestate_global->dispatch_table = PyObject_GetAttrString(copyreg, "dispatch_table"); + if (!_picklestate_global->dispatch_table) goto error; - extension_registry = \ + _picklestate_global->extension_registry = \ PyObject_GetAttrString(copyreg, "_extension_registry"); - if (!extension_registry) + if (!_picklestate_global->extension_registry) goto error; - inverted_registry = PyObject_GetAttrString(copyreg, "_inverted_registry"); - if (!inverted_registry) + _picklestate_global->inverted_registry = PyObject_GetAttrString(copyreg, "_inverted_registry"); + if (!_picklestate_global->inverted_registry) goto error; - extension_cache = PyObject_GetAttrString(copyreg, "_extension_cache"); - if (!extension_cache) + _picklestate_global->extension_cache = PyObject_GetAttrString(copyreg, "_extension_cache"); + if (!_picklestate_global->extension_cache) goto error; Py_CLEAR(copyreg); @@ -6348,75 +6421,75 @@ compat_pickle = PyImport_ImportModule("_compat_pickle"); if (!compat_pickle) goto error; - name_mapping_2to3 = PyObject_GetAttrString(compat_pickle, "NAME_MAPPING"); - if (!name_mapping_2to3) + _picklestate_global->name_mapping_2to3 = PyObject_GetAttrString(compat_pickle, "NAME_MAPPING"); + if (!_picklestate_global->name_mapping_2to3) goto error; - if (!PyDict_CheckExact(name_mapping_2to3)) { + if (!PyDict_CheckExact(_picklestate_global->name_mapping_2to3)) { PyErr_Format(PyExc_RuntimeError, "_compat_pickle.NAME_MAPPING should be a dict, not %.200s", - Py_TYPE(name_mapping_2to3)->tp_name); + Py_TYPE(_picklestate_global->name_mapping_2to3)->tp_name); goto error; } - import_mapping_2to3 = PyObject_GetAttrString(compat_pickle, + _picklestate_global->import_mapping_2to3 = PyObject_GetAttrString(compat_pickle, "IMPORT_MAPPING"); - if (!import_mapping_2to3) + if (!_picklestate_global->import_mapping_2to3) goto error; - if (!PyDict_CheckExact(import_mapping_2to3)) { + if (!PyDict_CheckExact(_picklestate_global->import_mapping_2to3)) { PyErr_Format(PyExc_RuntimeError, "_compat_pickle.IMPORT_MAPPING should be a dict, " - "not %.200s", Py_TYPE(import_mapping_2to3)->tp_name); + "not %.200s", Py_TYPE(_picklestate_global->import_mapping_2to3)->tp_name); goto error; } /* ... and the 3.x -> 2.x mapping tables */ - name_mapping_3to2 = PyObject_GetAttrString(compat_pickle, + _picklestate_global->name_mapping_3to2 = PyObject_GetAttrString(compat_pickle, "REVERSE_NAME_MAPPING"); - if (!name_mapping_3to2) + if (!_picklestate_global->name_mapping_3to2) goto error; - if (!PyDict_CheckExact(name_mapping_3to2)) { + if (!PyDict_CheckExact(_picklestate_global->name_mapping_3to2)) { PyErr_Format(PyExc_RuntimeError, "_compat_pickle.REVERSE_NAME_MAPPING should be a dict, " - "not %.200s", Py_TYPE(name_mapping_3to2)->tp_name); + "not %.200s", Py_TYPE(_picklestate_global->name_mapping_3to2)->tp_name); goto error; } - import_mapping_3to2 = PyObject_GetAttrString(compat_pickle, + _picklestate_global->import_mapping_3to2 = PyObject_GetAttrString(compat_pickle, "REVERSE_IMPORT_MAPPING"); - if (!import_mapping_3to2) + if (!_picklestate_global->import_mapping_3to2) goto error; - if (!PyDict_CheckExact(import_mapping_3to2)) { + if (!PyDict_CheckExact(_picklestate_global->import_mapping_3to2)) { PyErr_Format(PyExc_RuntimeError, "_compat_pickle.REVERSE_IMPORT_MAPPING should be a dict, " - "not %.200s", Py_TYPE(import_mapping_3to2)->tp_name); + "not %.200s", Py_TYPE(_picklestate_global->import_mapping_3to2)->tp_name); goto error; } Py_CLEAR(compat_pickle); - empty_tuple = PyTuple_New(0); - if (empty_tuple == NULL) + _picklestate_global->empty_tuple = PyTuple_New(0); + if (_picklestate_global->empty_tuple == NULL) goto error; - two_tuple = PyTuple_New(2); - if (two_tuple == NULL) + _picklestate_global->two_tuple = PyTuple_New(2); + if (_picklestate_global->two_tuple == NULL) goto error; /* We use this temp container with no regard to refcounts, or to * keeping containees alive. Exempt from GC, because we don't * want anything looking at two_tuple() by magic. */ - PyObject_GC_UnTrack(two_tuple); + PyObject_GC_UnTrack(_picklestate_global->two_tuple); return 0; error: Py_CLEAR(copyreg); - Py_CLEAR(dispatch_table); - Py_CLEAR(extension_registry); - Py_CLEAR(inverted_registry); - Py_CLEAR(extension_cache); + Py_CLEAR(_picklestate_global->dispatch_table); + Py_CLEAR(_picklestate_global->extension_registry); + Py_CLEAR(_picklestate_global->inverted_registry); + Py_CLEAR(_picklestate_global->extension_cache); Py_CLEAR(compat_pickle); - Py_CLEAR(name_mapping_2to3); - Py_CLEAR(import_mapping_2to3); - Py_CLEAR(name_mapping_3to2); - Py_CLEAR(import_mapping_3to2); - Py_CLEAR(empty_tuple); - Py_CLEAR(two_tuple); + Py_CLEAR(_picklestate_global->name_mapping_2to3); + Py_CLEAR(_picklestate_global->import_mapping_2to3); + Py_CLEAR(_picklestate_global->name_mapping_3to2); + Py_CLEAR(_picklestate_global->import_mapping_3to2); + Py_CLEAR(_picklestate_global->empty_tuple); + Py_CLEAR(_picklestate_global->two_tuple); return -1; } @@ -6424,60 +6497,79 @@ PyModuleDef_HEAD_INIT, "_pickle", pickle_module_doc, - -1, + sizeof(_picklestate), pickle_methods, NULL, - NULL, - NULL, - NULL + _pickle_traverse, + _pickle_clear, + _pickle_free }; PyMODINIT_FUNC PyInit__pickle(void) { PyObject *m; - - if (PyType_Ready(&Unpickler_Type) < 0) - return NULL; - if (PyType_Ready(&Pickler_Type) < 0) - return NULL; - if (PyType_Ready(&Pdata_Type) < 0) - return NULL; - if (PyType_Ready(&PicklerMemoProxyType) < 0) - return NULL; - if (PyType_Ready(&UnpicklerMemoProxyType) < 0) - return NULL; + _picklestate *state; /* Create the module and add the functions. */ m = PyModule_Create(&_picklemodule); if (m == NULL) return NULL; - Py_INCREF(&Pickler_Type); - if (PyModule_AddObject(m, "Pickler", (PyObject *)&Pickler_Type) < 0) + PyState_AddModule(m, &_picklemodule); + + state = _pickle_state(m); + + state->Unpickler_Type = PyType_FromSpec(&Unpickler_Type_spec); + if (state->Unpickler_Type == NULL) return NULL; - Py_INCREF(&Unpickler_Type); - if (PyModule_AddObject(m, "Unpickler", (PyObject *)&Unpickler_Type) < 0) + + state->Pickler_Type = PyType_FromSpec(&Pickler_Type_spec); + if (state->Pickler_Type == NULL) return NULL; + state->Pdata_Type = PyType_FromSpec(&Pdata_Type_spec); + if (state->Pdata_Type == NULL) + return NULL; + + state->PicklerMemoProxyType = PyType_FromSpec(&PicklerMemoProxyType_spec); + if (state->PicklerMemoProxyType == NULL) + return NULL; + + state->UnpicklerMemoProxyType = PyType_FromSpec(&UnpicklerMemoProxyType_spec); + if (state->UnpicklerMemoProxyType == NULL) + return NULL; + + Py_INCREF(state->Pickler_Type); + if (PyModule_AddObject(m, "Pickler", state->Pickler_Type) < 0) + return NULL; + Py_INCREF(state->Unpickler_Type); + if (PyModule_AddObject(m, "Unpickler", state->Unpickler_Type) < 0) + return NULL; + /* Initialize the exceptions. */ - PickleError = PyErr_NewException("_pickle.PickleError", NULL, NULL); - if (PickleError == NULL) + state->PickleError = PyErr_NewException("_pickle.PickleError", NULL, NULL); + if (state->PickleError == NULL) return NULL; - PicklingError = \ - PyErr_NewException("_pickle.PicklingError", PickleError, NULL); - if (PicklingError == NULL) + state->PicklingError = \ + PyErr_NewException("_pickle.PicklingError", state->PickleError, NULL); + if (state->PicklingError == NULL) return NULL; - UnpicklingError = \ - PyErr_NewException("_pickle.UnpicklingError", PickleError, NULL); - if (UnpicklingError == NULL) + state->UnpicklingError = \ + PyErr_NewException("_pickle.UnpicklingError", state->PickleError, NULL); + if (state->UnpicklingError == NULL) return NULL; - if (PyModule_AddObject(m, "PickleError", PickleError) < 0) + Py_INCREF(state->PickleError); + if (PyModule_AddObject(m, "PickleError", state->PickleError) < 0) return NULL; - if (PyModule_AddObject(m, "PicklingError", PicklingError) < 0) + + Py_INCREF(state->PicklingError); + if (PyModule_AddObject(m, "PicklingError", state->PicklingError) < 0) return NULL; - if (PyModule_AddObject(m, "UnpicklingError", UnpicklingError) < 0) + + Py_INCREF(state->UnpicklingError); + if (PyModule_AddObject(m, "UnpicklingError", state->UnpicklingError) < 0) return NULL; if (initmodule() < 0)