aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test/test_baseexception.py
diff options
context:
space:
mode:
authorOfey Chan <ofey206@gmail.com>2022-10-02 11:57:17 +0800
committerGitHub <noreply@github.com>2022-10-01 20:57:17 -0700
commitd63943860974f232b5f027dc6535d25d1b4d8fc0 (patch)
tree34ba0432e98431c890451f323cd79ecea5e2dc5b /Lib/test/test_baseexception.py
parent8baef8ae367041a5cfefb40b19c7b87e9bcb56a2 (diff)
downloadcpython-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.py25
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"""