From 0aaecb30483e98fc29c1f4253967d05da092f0c5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 25 Oct 2020 17:56:17 +0200 Subject: [3.9] bpo-41052: Fix pickling heap types implemented in C with protocols 0 and 1 (GH-22870). (GH-22963) (cherry picked from commit 8cd1dbae32d9303caac3a473d3332f17bc98c921) --- Lib/copyreg.py | 4 ++++ Lib/test/pickletester.py | 18 ++++++++++++++++++ .../Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst | 2 ++ Modules/_randommodule.c | 17 ----------------- Modules/clinic/_randommodule.c.h | 19 +------------------ 5 files changed, 25 insertions(+), 35 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst diff --git a/Lib/copyreg.py b/Lib/copyreg.py index dfc463c..7ab8c12 100644 --- a/Lib/copyreg.py +++ b/Lib/copyreg.py @@ -48,6 +48,7 @@ def _reconstructor(cls, base, state): return obj _HEAPTYPE = 1<<9 +_new_type = type(int.__new__) # Python code for object.__reduce_ex__ for protocols 0 and 1 @@ -57,6 +58,9 @@ def _reduce_ex(self, proto): for base in cls.__mro__: if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE: break + new = base.__new__ + if isinstance(new, _new_type) and new.__self__ is base: + break else: base = object # not really reachable if base is object: diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 94d42c4..3d54617 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1965,6 +1965,17 @@ class AbstractPickleTests(unittest.TestCase): self.assertEqual(B(x), B(y), detail) self.assertEqual(x.__dict__, y.__dict__, detail) + def test_newobj_overridden_new(self): + # Test that Python class with C implemented __new__ is pickleable + for proto in protocols: + x = MyIntWithNew2(1) + x.foo = 42 + s = self.dumps(x, proto) + y = self.loads(s) + self.assertIs(type(y), MyIntWithNew2) + self.assertEqual(int(y), 1) + self.assertEqual(y.foo, 42) + def test_newobj_not_class(self): # Issue 24552 global SimpleNewObj @@ -3085,6 +3096,13 @@ myclasses = [MyInt, MyFloat, MyStr, MyUnicode, MyTuple, MyList, MyDict, MySet, MyFrozenSet] +class MyIntWithNew(int): + def __new__(cls, value): + raise AssertionError + +class MyIntWithNew2(MyIntWithNew): + __new__ = int.__new__ + class SlotList(MyList): __slots__ = ["foo"] diff --git a/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst b/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst new file mode 100644 index 0000000..528e90e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-10-21-23-45-02.bpo-41052.3N7J2J.rst @@ -0,0 +1,2 @@ +Pickling heap types implemented in C with protocols 0 and 1 raises now an +error instead of producing incorrect data. diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 1b01491..a402b93 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -537,29 +537,12 @@ random_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } -/*[clinic input] - -_random.Random.__reduce__ - -[clinic start generated code]*/ - -static PyObject * -_random_Random___reduce___impl(RandomObject *self) -/*[clinic end generated code: output=ddea0dcdb60ffd6d input=bd38ec35fd157e0f]*/ -{ - PyErr_Format(PyExc_TypeError, - "cannot pickle %s object", - Py_TYPE(self)->tp_name); - return NULL; -} - static PyMethodDef random_methods[] = { _RANDOM_RANDOM_RANDOM_METHODDEF _RANDOM_RANDOM_SEED_METHODDEF _RANDOM_RANDOM_GETSTATE_METHODDEF _RANDOM_RANDOM_SETSTATE_METHODDEF _RANDOM_RANDOM_GETRANDBITS_METHODDEF - _RANDOM_RANDOM___REDUCE___METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/clinic/_randommodule.c.h b/Modules/clinic/_randommodule.c.h index 0a642df..a467811 100644 --- a/Modules/clinic/_randommodule.c.h +++ b/Modules/clinic/_randommodule.c.h @@ -114,21 +114,4 @@ _random_Random_getrandbits(RandomObject *self, PyObject *arg) exit: return return_value; } - -PyDoc_STRVAR(_random_Random___reduce____doc__, -"__reduce__($self, /)\n" -"--\n" -"\n"); - -#define _RANDOM_RANDOM___REDUCE___METHODDEF \ - {"__reduce__", (PyCFunction)_random_Random___reduce__, METH_NOARGS, _random_Random___reduce____doc__}, - -static PyObject * -_random_Random___reduce___impl(RandomObject *self); - -static PyObject * -_random_Random___reduce__(RandomObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _random_Random___reduce___impl(self); -} -/*[clinic end generated code: output=d8a99be3f1192219 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a7feb0c9c8d1b627 input=a9049054013a1b77]*/ -- cgit v0.12