https://github.com/python/cpython/commit/0906d2ab93fc9f4c7e0db031c965e7d8a0db7d37
commit: 0906d2ab93fc9f4c7e0db031c965e7d8a0db7d37
branch: main
author: John <[email protected]>
committer: markshannon <[email protected]>
date: 2026-10-01T12:15:51+01:00
summary:

gh-157468: Validate correct builtins used under JIT (GH-157766)

* Expose two possible builtin JIT gaps

* Add trace and runtime guard for builtin dict

* Check _GUARD_BUILTINS_IS_CANONICAL once per frame

* Add check and fix for globals being folded

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-09-18-20-24-43.gh-issue-157468.zVIAva.rst
M Include/internal/pycore_optimizer_types.h
M Include/internal/pycore_uop_ids.h
M Include/internal/pycore_uop_metadata.h
M Lib/test/test_capi/test_opt.py
M Objects/dictobject.c
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/optimizer_bytecodes.c
M Python/optimizer_cases.c.h
M Python/optimizer_symbols.c

diff --git a/Include/internal/pycore_optimizer_types.h 
b/Include/internal/pycore_optimizer_types.h
index a722652cc8163a..c1928ec9ebdac3 100644
--- a/Include/internal/pycore_optimizer_types.h
+++ b/Include/internal/pycore_optimizer_types.h
@@ -140,6 +140,7 @@ typedef union {
 
 typedef struct _Py_UOpsAbstractFrame {
     bool globals_watched;
+    bool builtins_checked;
     // The version number of the globals dicts, once checked. 0 if unchecked.
     uint32_t globals_checked_version;
     // Max stacklen
diff --git a/Include/internal/pycore_uop_ids.h 
b/Include/internal/pycore_uop_ids.h
index 840a32f0e4481f..ba6e0252024a6d 100644
--- a/Include/internal/pycore_uop_ids.h
+++ b/Include/internal/pycore_uop_ids.h
@@ -142,6 +142,7 @@ enum {
     _GUARD_BIT_IS_UNSET_POP_5,
     _GUARD_BIT_IS_UNSET_POP_6,
     _GUARD_BIT_IS_UNSET_POP_7,
+    _GUARD_BUILTINS_IS_CANONICAL,
     _GUARD_CALLABLE_BUILTIN_CLASS,
     _GUARD_CALLABLE_BUILTIN_FAST,
     _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS,
@@ -365,7 +366,7 @@ enum {
     _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE,
     _YIELD_VALUE,
 };
-#define MAX_UOP_ID 653
+#define MAX_UOP_ID 654
 
 #define _BUILD_INTERPOLATION BUILD_INTERPOLATION
 #define _BUILD_LIST BUILD_LIST
@@ -750,6 +751,10 @@ enum {
     _GUARD_BIT_IS_UNSET_POP_7_r10,
     _GUARD_BIT_IS_UNSET_POP_7_r21,
     _GUARD_BIT_IS_UNSET_POP_7_r32,
+    _GUARD_BUILTINS_IS_CANONICAL_r00,
+    _GUARD_BUILTINS_IS_CANONICAL_r11,
+    _GUARD_BUILTINS_IS_CANONICAL_r22,
+    _GUARD_BUILTINS_IS_CANONICAL_r33,
     _GUARD_CALLABLE_BUILTIN_CLASS_r00,
     _GUARD_CALLABLE_BUILTIN_FAST_r00,
     _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS_r00,
@@ -1439,7 +1444,7 @@ enum {
     _WITH_EXCEPT_START_r33,
     _YIELD_VALUE_r11,
 };
-#define MAX_UOP_REGS_ID 1650
+#define MAX_UOP_REGS_ID 1655
 
 #ifdef __cplusplus
 }
diff --git a/Include/internal/pycore_uop_metadata.h 
b/Include/internal/pycore_uop_metadata.h
index 1c440fe9f1e978..177564a7545941 100644
--- a/Include/internal/pycore_uop_metadata.h
+++ b/Include/internal/pycore_uop_metadata.h
@@ -196,6 +196,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
     [_GUARD_GLOBALS_VERSION] = HAS_DEOPT_FLAG,
     [_LOAD_GLOBAL_MODULE] = HAS_DEOPT_FLAG,
     [_LOAD_GLOBAL_BUILTINS] = HAS_DEOPT_FLAG,
+    [_GUARD_BUILTINS_IS_CANONICAL] = HAS_DEOPT_FLAG,
     [_DELETE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ERROR_FLAG | 
HAS_ESCAPES_FLAG,
     [_MAKE_CELL] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | 
HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
     [_DELETE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ERROR_FLAG | 
HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
@@ -1894,6 +1895,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
             { -1, -1, -1 },
         },
     },
+    [_GUARD_BUILTINS_IS_CANONICAL] = {
+        .best = { 0, 1, 2, 3 },
+        .entries = {
+            { 0, 0, _GUARD_BUILTINS_IS_CANONICAL_r00 },
+            { 1, 1, _GUARD_BUILTINS_IS_CANONICAL_r11 },
+            { 2, 2, _GUARD_BUILTINS_IS_CANONICAL_r22 },
+            { 3, 3, _GUARD_BUILTINS_IS_CANONICAL_r33 },
+        },
+    },
     [_DELETE_FAST] = {
         .best = { 0, 0, 0, 0 },
         .entries = {
@@ -4315,6 +4325,10 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
     [_GUARD_GLOBALS_VERSION_r33] = _GUARD_GLOBALS_VERSION,
     [_LOAD_GLOBAL_MODULE_r01] = _LOAD_GLOBAL_MODULE,
     [_LOAD_GLOBAL_BUILTINS_r01] = _LOAD_GLOBAL_BUILTINS,
+    [_GUARD_BUILTINS_IS_CANONICAL_r00] = _GUARD_BUILTINS_IS_CANONICAL,
+    [_GUARD_BUILTINS_IS_CANONICAL_r11] = _GUARD_BUILTINS_IS_CANONICAL,
+    [_GUARD_BUILTINS_IS_CANONICAL_r22] = _GUARD_BUILTINS_IS_CANONICAL,
+    [_GUARD_BUILTINS_IS_CANONICAL_r33] = _GUARD_BUILTINS_IS_CANONICAL,
     [_DELETE_FAST_r00] = _DELETE_FAST,
     [_MAKE_CELL_r00] = _MAKE_CELL,
     [_DELETE_DEREF_r00] = _DELETE_DEREF,
@@ -5292,6 +5306,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] 
= {
     [_GUARD_BIT_IS_UNSET_POP_7_r10] = "_GUARD_BIT_IS_UNSET_POP_7_r10",
     [_GUARD_BIT_IS_UNSET_POP_7_r21] = "_GUARD_BIT_IS_UNSET_POP_7_r21",
     [_GUARD_BIT_IS_UNSET_POP_7_r32] = "_GUARD_BIT_IS_UNSET_POP_7_r32",
+    [_GUARD_BUILTINS_IS_CANONICAL] = "_GUARD_BUILTINS_IS_CANONICAL",
+    [_GUARD_BUILTINS_IS_CANONICAL_r00] = "_GUARD_BUILTINS_IS_CANONICAL_r00",
+    [_GUARD_BUILTINS_IS_CANONICAL_r11] = "_GUARD_BUILTINS_IS_CANONICAL_r11",
+    [_GUARD_BUILTINS_IS_CANONICAL_r22] = "_GUARD_BUILTINS_IS_CANONICAL_r22",
+    [_GUARD_BUILTINS_IS_CANONICAL_r33] = "_GUARD_BUILTINS_IS_CANONICAL_r33",
     [_GUARD_CALLABLE_BUILTIN_CLASS] = "_GUARD_CALLABLE_BUILTIN_CLASS",
     [_GUARD_CALLABLE_BUILTIN_CLASS_r00] = "_GUARD_CALLABLE_BUILTIN_CLASS_r00",
     [_GUARD_CALLABLE_BUILTIN_FAST] = "_GUARD_CALLABLE_BUILTIN_FAST",
@@ -6488,6 +6507,8 @@ int _PyUop_num_popped(int opcode, int oparg)
             return 0;
         case _LOAD_GLOBAL_BUILTINS:
             return 0;
+        case _GUARD_BUILTINS_IS_CANONICAL:
+            return 0;
         case _DELETE_FAST:
             return 0;
         case _MAKE_CELL:
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index 64b6e82936d2f1..88077aacecbf5b 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -1,3 +1,4 @@
+import builtins
 import contextlib
 import dis
 import itertools
@@ -5276,6 +5277,119 @@ def jitted(funcs):
         with self.assertRaises(NameError):
             jitted([f, f_with_bad_globals])
 
+    def test_jitted_code_sees_changed_copied_builtins(self):
+        # Trace-time check.  The traced function's builtins is a copy of the
+        # canonical dict with the same keys version, so a version check
+        # cannot tell them apart.  The optimizer must see that func_builtins
+        # is not interp->builtins and keep _LOAD_GLOBAL_BUILTINS, which reads
+        # the frame's own dict, rather than fold a constant from the
+        # canonical one.  No runtime guard is involved.
+
+        def f(n):
+            return [len("hello") for _ in range(n)]
+
+        copied_builtins = vars(builtins).copy()
+        f = types.FunctionType(f.__code__, {"__builtins__": copied_builtins})
+
+        f(TIER2_THRESHOLD)
+        ex = get_first_executor(f)
+        self.assertIsNotNone(ex)
+        # Not folded: the load must still consult the frame's builtins.
+        self.assertIn("_LOAD_GLOBAL_BUILTINS", get_opnames(ex))
+
+        # Replacing an existing value does not change the keys version.
+        copied_builtins["len"] = lambda s: 42
+        self.assertEqual(f(8), [42] * 8)
+
+    def test_jitted_code_sees_changed_copied_globals(self):
+        # Copying a dict must not carry over the keys version of the source.
+        # The optimizer folds a global to a constant guarded only by the
+        # globals keys version plus a watcher on the traced dict.  A copy is
+        # not watched, and replacing an existing value does not change the
+        # keys version, so a function whose globals are a copy of the traced
+        # dict would otherwise pass _GUARD_GLOBALS_VERSION and see the stale
+        # constant.
+        def f(n):
+            for _ in range(n):
+                x = COPIED_GLOBAL
+            return x
+
+        for copy in (dict.copy, dict):
+            with self.subTest(copy=copy):
+                original = {"COPIED_GLOBAL": 1}
+                # A fresh code object, so that each subtest traces anew.
+                f_original = types.FunctionType(f.__code__.replace(), original)
+                self.assertEqual(f_original(TIER2_THRESHOLD), 1)
+                ex = get_first_executor(f_original)
+                self.assertIsNotNone(ex)
+                uops = get_opnames(ex)
+                self.assertIn("_GUARD_GLOBALS_VERSION", uops)
+                # The global was folded to a constant.
+                self.assertNotIn("_LOAD_GLOBAL_MODULE", uops)
+
+                copied = copy(original)
+                copied["COPIED_GLOBAL"] = 2
+                # Share the code object, so that the same executor is entered.
+                f_copied = types.FunctionType(f_original.__code__, copied)
+                self.assertEqual(f_copied(TIER2_THRESHOLD), 2)
+                self.assertEqual(f_original(TIER2_THRESHOLD), 1)
+
+    def test_jitted_code_sees_different_builtins(self):
+        # Runtime check.  The traced function's builtins IS the canonical
+        # dict, so folding len to a constant is correct at trace time.
+        # A second function sharing the code object then enters the same
+        # executor with other builtins, so only the runtime guard on the
+        # executing frame's builtins can catch it.
+        def f(n):
+            return [len("hello") for _ in range(n)]
+
+        namespace = {"__builtins__": builtins}
+        f_canonical = types.FunctionType(f.__code__, namespace)
+        copied_builtins = vars(builtins).copy()
+        namespace["__builtins__"] = copied_builtins
+        f_copied = types.FunctionType(f.__code__, namespace)
+
+
+        f_canonical(TIER2_THRESHOLD)
+        ex = get_first_executor(f_canonical)
+        self.assertIsNotNone(ex)
+        self.assertIn("_GUARD_BUILTINS_IS_CANONICAL", get_opnames(ex))
+
+        copied_builtins["len"] = lambda s: 42
+        # The executor's owner still sees the canonical len.
+        self.assertEqual(f_canonical(8), [5] * 8)
+        # A different function enters the same executor with other builtins.
+        self.assertEqual(f_copied(8), [42] * 8)
+
+    def test_builtins_guard_emitted_once_per_frame(self):
+        # A frame's builtins cannot change once the frame is pushed, so
+        # repeated builtin loads in one frame share a single guard, just as
+        # they already share a single _GUARD_GLOBALS_VERSION.
+
+        def warmup(n):
+            x = 0
+            for _ in range(n):
+                x += len("ab")
+            return x
+
+        def one_frame(n):
+            x = 0
+            for _ in range(n):
+                x += len("ab") + abs(-1) + ord("c")
+            return x
+
+        # The optimizer context is reused for every compilation, so compile an
+        # unrelated trace first: state that is not reset per frame leaks here.
+        warmup(TIER2_THRESHOLD)
+        self.assertIsNotNone(get_first_executor(warmup))
+
+        _, ex = self._run_with_optimizer(one_frame, TIER2_THRESHOLD)
+        self.assertIsNotNone(ex)
+        uop_names = get_opnames(ex)
+        self.assertNotIn("_LOAD_GLOBAL_BUILTINS", uop_names)  # all folded
+        self.assertEqual(uop_names.count("_GUARD_BUILTINS_IS_CANONICAL"), 1)
+        self.assertEqual(uop_names.count("_GUARD_GLOBALS_VERSION"), 1)
+
     def test_reference_tracking_across_call_doesnt_crash(self):
 
         def f1():
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-18-20-24-43.gh-issue-157468.zVIAva.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-18-20-24-43.gh-issue-157468.zVIAva.rst
new file mode 100644
index 00000000000000..bec475ae711423
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-18-20-24-43.gh-issue-157468.zVIAva.rst
@@ -0,0 +1,7 @@
+Fix the JIT optimizer folding a builtin name to a constant taken from the
+interpreter's builtins dictionary even when the running function uses a
+different ``__builtins__`` mapping, such as one created with
+``vars(builtins).copy()``. The optimizer now only folds when the function's
+builtins is the interpreter's, and the folded constant is guarded at runtime so
+that another function sharing the same code object but a different builtins
+mapping does not use it.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 15377ac083c2b2..49eb8481e128d0 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1041,6 +1041,10 @@ clone_combined_dict_keys(PyDictObject *orig)
 
     memcpy(keys, orig->ma_keys, keys_size);
 
+    /* The keys version must be unique per keys object: the specializer
+       and the JIT optimizer rely on it to identify a dict's keys. */
+    keys->dk_version = 0;
+
     /* After copying key/value pairs, we need to incref all
        keys and values and they are about to be co-owned by a
        new dict object. */
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 8dfb76ef7884d1..3f329274f06b11 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2356,6 +2356,10 @@ dummy_func(
             STAT_INC(LOAD_GLOBAL, hit);
         }
 
+        tier2 op(_GUARD_BUILTINS_IS_CANONICAL, (--)) {
+            DEOPT_IF(BUILTINS() != tstate->interp->builtins);
+        }
+
         macro(LOAD_GLOBAL_MODULE) =
             unused/1 + // Skip over the counter
             NOP + // For guard insertion in the JIT optimizer
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index b60e9b2b52daa8..400f07b58e7fa5 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -10482,6 +10482,76 @@
             break;
         }
 
+        case _GUARD_BUILTINS_IS_CANONICAL_r00: {
+            CHECK_CURRENT_CACHED_VALUES(0);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            if (BUILTINS() != tstate->interp->builtins) {
+                UOP_STAT_INC(uopcode, miss);
+                SET_CURRENT_CACHED_VALUES(0);
+                JUMP_TO_JUMP_TARGET();
+            }
+            SET_CURRENT_CACHED_VALUES(0);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            break;
+        }
+
+        case _GUARD_BUILTINS_IS_CANONICAL_r11: {
+            CHECK_CURRENT_CACHED_VALUES(1);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            _PyStackRef _stack_item_0 = _tos_cache0;
+            if (BUILTINS() != tstate->interp->builtins) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache0 = _stack_item_0;
+                SET_CURRENT_CACHED_VALUES(1);
+                JUMP_TO_JUMP_TARGET();
+            }
+            _tos_cache0 = _stack_item_0;
+            SET_CURRENT_CACHED_VALUES(1);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            break;
+        }
+
+        case _GUARD_BUILTINS_IS_CANONICAL_r22: {
+            CHECK_CURRENT_CACHED_VALUES(2);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            _PyStackRef _stack_item_0 = _tos_cache0;
+            _PyStackRef _stack_item_1 = _tos_cache1;
+            if (BUILTINS() != tstate->interp->builtins) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache1 = _stack_item_1;
+                _tos_cache0 = _stack_item_0;
+                SET_CURRENT_CACHED_VALUES(2);
+                JUMP_TO_JUMP_TARGET();
+            }
+            _tos_cache1 = _stack_item_1;
+            _tos_cache0 = _stack_item_0;
+            SET_CURRENT_CACHED_VALUES(2);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            break;
+        }
+
+        case _GUARD_BUILTINS_IS_CANONICAL_r33: {
+            CHECK_CURRENT_CACHED_VALUES(3);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            _PyStackRef _stack_item_0 = _tos_cache0;
+            _PyStackRef _stack_item_1 = _tos_cache1;
+            _PyStackRef _stack_item_2 = _tos_cache2;
+            if (BUILTINS() != tstate->interp->builtins) {
+                UOP_STAT_INC(uopcode, miss);
+                _tos_cache2 = _stack_item_2;
+                _tos_cache1 = _stack_item_1;
+                _tos_cache0 = _stack_item_0;
+                SET_CURRENT_CACHED_VALUES(3);
+                JUMP_TO_JUMP_TARGET();
+            }
+            _tos_cache2 = _stack_item_2;
+            _tos_cache1 = _stack_item_1;
+            _tos_cache0 = _stack_item_0;
+            SET_CURRENT_CACHED_VALUES(3);
+            ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
+            break;
+        }
+
         case _DELETE_FAST_r00: {
             CHECK_CURRENT_CACHED_VALUES(0);
             ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c
index ca4ce4f733ea34..6284885c428832 100644
--- a/Python/optimizer_bytecodes.c
+++ b/Python/optimizer_bytecodes.c
@@ -2531,13 +2531,24 @@ dummy_func(void) {
         else if (interp->rare_events.builtin_dict >= 
_Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
             /* Do nothing */
         }
+        else if (ctx->frame->func == NULL ||
+                 ctx->frame->func->func_builtins != builtins) {
+            /* Do nothing */
+        }
         else {
             if (!ctx->builtins_watched) {
                 PyDict_Watch(BUILTINS_WATCHER_ID, builtins);
                 ctx->builtins_watched = true;
             }
-            if (ctx->frame->globals_checked_version != 0 && 
ctx->frame->globals_watched) {
+            if (ctx->frame->globals_checked_version != 0 &&
+                ctx->frame->globals_watched)
+            {
                 cnst = convert_global_to_const(this_instr, builtins);
+                if (cnst != NULL && !ctx->frame->builtins_checked) {
+                    ctx->frame->builtins_checked = true;
+                    ADD_OP(_GUARD_BUILTINS_IS_CANONICAL, 0, 0);
+                    ADD_OP(this_instr->opcode, 0, (uintptr_t)cnst);
+                }
             }
         }
         if (cnst == NULL) {
diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h
index 57a9539016bbb2..bd3ed9ce99a555 100644
--- a/Python/optimizer_cases.c.h
+++ b/Python/optimizer_cases.c.h
@@ -2301,13 +2301,23 @@
             }
             else if (interp->rare_events.builtin_dict >= 
_Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
             }
+            else if (ctx->frame->func == NULL ||
+                 ctx->frame->func->func_builtins != builtins) {
+            }
             else {
                 if (!ctx->builtins_watched) {
                     PyDict_Watch(BUILTINS_WATCHER_ID, builtins);
                     ctx->builtins_watched = true;
                 }
-                if (ctx->frame->globals_checked_version != 0 && 
ctx->frame->globals_watched) {
+                if (ctx->frame->globals_checked_version != 0 &&
+                    ctx->frame->globals_watched)
+                {
                     cnst = convert_global_to_const(this_instr, builtins);
+                    if (cnst != NULL && !ctx->frame->builtins_checked) {
+                        ctx->frame->builtins_checked = true;
+                        ADD_OP(_GUARD_BUILTINS_IS_CANONICAL, 0, 0);
+                        ADD_OP(this_instr->opcode, 0, (uintptr_t)cnst);
+                    }
                 }
             }
             if (cnst == NULL) {
@@ -2328,6 +2338,10 @@
             break;
         }
 
+        case _GUARD_BUILTINS_IS_CANONICAL: {
+            break;
+        }
+
         case _DELETE_FAST: {
             break;
         }
diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c
index 3147e9c5065edd..eaa4c8dbbdc5de 100644
--- a/Python/optimizer_symbols.c
+++ b/Python/optimizer_symbols.c
@@ -1378,6 +1378,7 @@ _Py_uop_frame_new(
     frame->stack_pointer = frame->stack;
     frame->globals_checked_version = 0;
     frame->globals_watched = false;
+    frame->builtins_checked = false;
     frame->func = NULL;
     frame->caller = false;
     frame->is_c_recursion_checked = false;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to