]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-123185: Check for `NULL` after calling `_PyEvalFramePushAndInit` (GH-123194)
authorMark Shannon <mark@hotpy.org>
Wed, 21 Aug 2024 11:44:56 +0000 (12:44 +0100)
committerGitHub <noreply@github.com>
Wed, 21 Aug 2024 11:44:56 +0000 (12:44 +0100)
Include/internal/pycore_uop_metadata.h
Lib/test/test_class.py
Python/bytecodes.c
Python/executor_cases.c.h
Python/generated_cases.c.h

index 15c0ac110301c7143756bab1c2d8a3c69efa66e8..e2cba4dc0dfc818933245d628b18b5d799c2266e 100644 (file)
@@ -226,7 +226,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
     [_CALL_STR_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
     [_CALL_TUPLE_1] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
     [_CHECK_AND_ALLOCATE_OBJECT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
-    [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
+    [_CREATE_INIT_FRAME] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
     [_EXIT_INIT_CHECK] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
     [_CALL_BUILTIN_CLASS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
     [_CALL_BUILTIN_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
index d1f828b1ed824d7357056797667aa39090afa410..f6ec213b84e664359347583a1a5b068dfd206345 100644 (file)
@@ -787,6 +787,19 @@ class ClassTests(unittest.TestCase):
             Type(i)
         self.assertEqual(calls, 100)
 
+    def test_specialization_class_call_doesnt_crash(self):
+        # gh-123185
+
+        class Foo:
+            def __init__(self, arg):
+                pass
+
+        for _ in range(8):
+            try:
+                Foo()
+            except:
+                pass
+
 
 from _testinternalcapi import has_inline_values
 
index ec0f6ab8fde9800bb2773a5894ed07d53fcf58ba..3edd374654178a06c01e2c9ef4d947a4f0e744c1 100644 (file)
@@ -3584,8 +3584,12 @@ dummy_func(
             args[-1] = self;
             init_frame = _PyEvalFramePushAndInit(
                 tstate, init_func, NULL, args-1, oparg+1, NULL, shim);
-            frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
             SYNC_SP();
+            if (init_frame == NULL) {
+                _PyEval_FrameClearAndPop(tstate, shim);
+                ERROR_NO_POP();
+            }
+            frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
             /* Account for pushing the extra frame.
              * We don't check recursion depth here,
              * as it will be checked after start_frame */
index 9226b7a4e5d4bc39738325d781951e6fd6507f1e..1db8e5067322ee650349aa8c954f0e45e92d6001 100644 (file)
             args[-1] = self;
             init_frame = _PyEvalFramePushAndInit(
                 tstate, init_func, NULL, args-1, oparg+1, NULL, shim);
-            frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
             stack_pointer += -2 - oparg;
             assert(WITHIN_STACK_BOUNDS());
+            if (init_frame == NULL) {
+                _PyEval_FrameClearAndPop(tstate, shim);
+                JUMP_TO_ERROR();
+            }
+            frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
             /* Account for pushing the extra frame.
              * We don't check recursion depth here,
              * as it will be checked after start_frame */
index 27971ce75464f0e54002b1588135eb3e8dc1fa80..f4a5d2a9650f58f627b87d56f4195fd56697f289 100644 (file)
                 args[-1] = self;
                 init_frame = _PyEvalFramePushAndInit(
                     tstate, init_func, NULL, args-1, oparg+1, NULL, shim);
-                frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
                 stack_pointer += -2 - oparg;
                 assert(WITHIN_STACK_BOUNDS());
+                if (init_frame == NULL) {
+                    _PyEval_FrameClearAndPop(tstate, shim);
+                    goto error;
+                }
+                frame->return_offset = 1 + INLINE_CACHE_ENTRIES_CALL;
                 /* Account for pushing the extra frame.
                  * We don't check recursion depth here,
                  * as it will be checked after start_frame */