diff options
author | Ofey Chan <ofey206@gmail.com> | 2022-10-02 11:57:17 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-01 20:57:17 -0700 |
commit | d63943860974f232b5f027dc6535d25d1b4d8fc0 (patch) | |
tree | 34ba0432e98431c890451f323cd79ecea5e2dc5b /Lib/test/test_baseexception.py | |
parent | 8baef8ae367041a5cfefb40b19c7b87e9bcb56a2 (diff) | |
download | cpython-d63943860974f232b5f027dc6535d25d1b4d8fc0.tar.gz cpython-d63943860974f232b5f027dc6535d25d1b4d8fc0.zip |
gh-97591: In `Exception.__setstate__()` acquire strong references before calling `tp_hash` slot (#97700)
Diffstat (limited to 'Lib/test/test_baseexception.py')
-rw-r--r-- | Lib/test/test_baseexception.py | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/Lib/test/test_baseexception.py b/Lib/test/test_baseexception.py index 0061b3fa8e6..4c3cf0b964a 100644 --- a/Lib/test/test_baseexception.py +++ b/Lib/test/test_baseexception.py @@ -114,6 +114,31 @@ class ExceptionClassTests(unittest.TestCase): [repr(exc), exc.__class__.__name__ + '()']) self.interface_test_driver(results) + def test_setstate_refcount_no_crash(self): + # gh-97591: Acquire strong reference before calling tp_hash slot + # in PyObject_SetAttr. + import gc + d = {} + class HashThisKeyWillClearTheDict(str): + def __hash__(self) -> int: + d.clear() + return super().__hash__() + class Value(str): + pass + exc = Exception() + + d[HashThisKeyWillClearTheDict()] = Value() # refcount of Value() is 1 now + + # Exception.__setstate__ should aquire a strong reference of key and + # value in the dict. Otherwise, Value()'s refcount would go below + # zero in the tp_hash call in PyObject_SetAttr(), and it would cause + # crash in GC. + exc.__setstate__(d) # __hash__() is called again here, clearing the dict. + + # This GC would crash if the refcount of Value() goes below zero. + gc.collect() + + class UsageTests(unittest.TestCase): """Test usage of exceptions""" |