From 756774e1320e13e395446091ef67c52a0ee5c887 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 5 May 2025 16:58:51 +0200 Subject: [PATCH 1/4] gh-133441: Fix STORE_ATTR_WITH_HINT bytecode Deoptimize if the dict is a dict subclass. --- Lib/test/test_dict.py | 18 ++++++++++++++++++ ...5-05-05-17-02-08.gh-issue-133441.EpjHD4.rst | 2 ++ Python/bytecodes.c | 3 ++- Python/generated_cases.c.h | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 4030716efb51f9..72c4f049f5b37c 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1594,6 +1594,24 @@ def make_pairs(): self.assertEqual(d.get(key3_3), 44) self.assertGreaterEqual(eq_count, 1) + def test_store_attr_with_hint(self): + # gh-133441: Regression test for STORE_ATTR_WITH_HINT bytecode + class Node: + def __init__(self): + self.parents = {} + + def __setstate__(self, data_dict): + self.__dict__ = data_dict + self.parents = {} + + class Dict(dict): + pass + + obj = Node() + obj.__setstate__({'parents': {}}) + obj.__setstate__({'parents': {}}) + obj.__setstate__(Dict({'parents': {}})) + class CAPITest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst new file mode 100644 index 00000000000000..ef9ca4d78c89aa --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst @@ -0,0 +1,2 @@ +Fix ``STORE_ATTR_WITH_HINT`` bytecode: deoptimize if the dictionary is a +dict subclass. Patch by Victor Stinner. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6d5a42943b0d98..1da434bbbc892a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2149,7 +2149,8 @@ dummy_func( assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictObject *dict = _PyObject_GetManagedDict(owner); DEOPT_IF(dict == NULL); - assert(PyDict_CheckExact((PyObject *)dict)); + DEOPT_IF(!PyDict_CheckExact((PyObject *)dict)); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries); PyObject *old_value; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9665774cf9c03c..be00bf6eb6a39e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5591,7 +5591,7 @@ assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictObject *dict = _PyObject_GetManagedDict(owner); DEOPT_IF(dict == NULL, STORE_ATTR); - assert(PyDict_CheckExact((PyObject *)dict)); + DEOPT_IF(!PyDict_CheckExact((PyObject *)dict), STORE_ATTR); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; From 0b4626f3b7e186b39be3e9e82eb905c6f82e7eef Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 May 2025 08:08:13 +0200 Subject: [PATCH 2/4] Move test to test_opcache --- Lib/test/test_dict.py | 18 ------------------ Lib/test/test_opcache.py | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 72c4f049f5b37c..4030716efb51f9 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1594,24 +1594,6 @@ def make_pairs(): self.assertEqual(d.get(key3_3), 44) self.assertGreaterEqual(eq_count, 1) - def test_store_attr_with_hint(self): - # gh-133441: Regression test for STORE_ATTR_WITH_HINT bytecode - class Node: - def __init__(self): - self.parents = {} - - def __setstate__(self, data_dict): - self.__dict__ = data_dict - self.parents = {} - - class Dict(dict): - pass - - obj = Node() - obj.__setstate__({'parents': {}}) - obj.__setstate__({'parents': {}}) - obj.__setstate__(Dict({'parents': {}})) - class CAPITest(unittest.TestCase): diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index c4fcc1993ca627..aeb4de6caa527d 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1155,6 +1155,24 @@ class D(dict): pass {'a':1, 'b':2} ) + def test_store_attr_with_hint(self): + # gh-133441: Regression test for STORE_ATTR_WITH_HINT bytecode + class Node: + def __init__(self): + self.parents = {} + + def __setstate__(self, data_dict): + self.__dict__ = data_dict + self.parents = {} + + class Dict(dict): + pass + + obj = Node() + obj.__setstate__({'parents': {}}) + obj.__setstate__({'parents': {}}) + obj.__setstate__(Dict({'parents': {}})) + if __name__ == "__main__": unittest.main() From 084a9ae347710a3477098c99aaa5085aa192f21b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 May 2025 13:24:33 +0200 Subject: [PATCH 3/4] Update Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst Co-authored-by: Peter Bierma --- .../2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst index ef9ca4d78c89aa..553ff797daf8a5 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst @@ -1,2 +1 @@ -Fix ``STORE_ATTR_WITH_HINT`` bytecode: deoptimize if the dictionary is a -dict subclass. Patch by Victor Stinner. +Fix crash upon calling :meth:`~object.__setstate__` with a :class:`dict` subclass. Patch by Victor Stinner. From d4ed1e962f5ad26e578a1bf8e379bba749631e01 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 May 2025 13:29:37 +0200 Subject: [PATCH 4/4] Adjust NEWS entry --- .../2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst index 553ff797daf8a5..4e893045b1d60e 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-05-17-02-08.gh-issue-133441.EpjHD4.rst @@ -1 +1,2 @@ -Fix crash upon calling :meth:`~object.__setstate__` with a :class:`dict` subclass. Patch by Victor Stinner. +Fix crash upon setting an attribute with a :class:`dict` subclass. +Patch by Victor Stinner.