diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-06-11 03:52:41 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-11 03:52:41 (GMT) |
commit | 54fe3d57bf5078f2d019df20c2db8028eb1a9e0f (patch) | |
tree | 52dfca04646e6e98feec1e90b35b61336893b20d /Lib/test/pickletester.py | |
parent | 0aa9ec9f5d1154319ec4332315fff373505b6373 (diff) | |
download | cpython-54fe3d57bf5078f2d019df20c2db8028eb1a9e0f.zip cpython-54fe3d57bf5078f2d019df20c2db8028eb1a9e0f.tar.gz cpython-54fe3d57bf5078f2d019df20c2db8028eb1a9e0f.tar.bz2 |
gh-92930: _pickle.c: Acquire strong references before calling save() (GH-92931)
(cherry picked from commit 4c496f1f115a7910d4606b4de233d14874c77bfa)
Co-authored-by: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com>
Diffstat (limited to 'Lib/test/pickletester.py')
-rw-r--r-- | Lib/test/pickletester.py | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index d0ea7d0..21419e1 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -3035,6 +3035,67 @@ class AbstractPickleTests: # 2-D, non-contiguous check_array(arr[::2]) + def test_evil_class_mutating_dict(self): + # https://github.com/python/cpython/issues/92930 + from random import getrandbits + + global Bad + class Bad: + def __eq__(self, other): + return ENABLED + def __hash__(self): + return 42 + def __reduce__(self): + if getrandbits(6) == 0: + collection.clear() + return (Bad, ()) + + for proto in protocols: + for _ in range(20): + ENABLED = False + collection = {Bad(): Bad() for _ in range(20)} + for bad in collection: + bad.bad = bad + bad.collection = collection + ENABLED = True + try: + data = self.dumps(collection, proto) + self.loads(data) + except RuntimeError as e: + expected = "changed size during iteration" + self.assertIn(expected, str(e)) + + def test_evil_pickler_mutating_collection(self): + # https://github.com/python/cpython/issues/92930 + if not hasattr(self, "pickler"): + raise self.skipTest(f"{type(self)} has no associated pickler type") + + global Clearer + class Clearer: + pass + + def check(collection): + class EvilPickler(self.pickler): + def persistent_id(self, obj): + if isinstance(obj, Clearer): + collection.clear() + return None + pickler = EvilPickler(io.BytesIO(), proto) + try: + pickler.dump(collection) + except RuntimeError as e: + expected = "changed size during iteration" + self.assertIn(expected, str(e)) + + for proto in protocols: + check([Clearer()]) + check([Clearer(), Clearer()]) + check({Clearer()}) + check({Clearer(), Clearer()}) + check({Clearer(): 1}) + check({Clearer(): 1, Clearer(): 2}) + check({1: Clearer(), 2: Clearer()}) + class BigmemPickleTests: |