[3.14] gh-154902: Type-check the SET_ADD operand (#155072)

This commit is contained in:
Timofei Ivankov authored and GitHub committed 2026-08-05 07:24:50 -07:00
1 parent e7a45f431b
commit c21e7c45a9
5 files changed
+55 -3

No files matched your search

+16
View File
@@ -1,5 +1,6 @@
import annotationlib
import inspect
import itertools
import textwrap
import types
import unittest
@@ -896,3 +897,18 @@ class RegressionTests(unittest.TestCase):
mod = build_module(code)
annos = mod.__annotations__
self.assertEqual(annos, {"annotated_name": 0})
# gh-154902
def test_conditional_annotations_rebound(self):
# user code can rebind __conditional_annotations__ to any object
lefts = ("__conditional_annotations__",
'globals()["__conditional_annotations__"]')
values = ("0", "{}", "[]", "''", "object()", "frozenset()")
for left, value in itertools.product(lefts, values):
with self.subTest(left=left, value=value):
code = f"""
{left} = {value}
x: int
"""
with self.assertRaises(TypeError):
run_code(code)
@@ -0,0 +1,2 @@
Fix a crash when ``__conditional_annotations__`` is rebound to a non-set
object.
+9 -1
View File
@@ -1056,7 +1056,15 @@ dummy_func(
}
inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) {
int err = _PySet_AddTakeRef((PySetObject *)PyStackRef_AsPyObjectBorrow(set),
PyObject *set_o = PyStackRef_AsPyObjectBorrow(set);
// gh-154902: user code can rebind __conditional_annotations__
if (!PySet_CheckExact(set_o)) {
_PyErr_Format(tstate, PyExc_TypeError,
"'%T' object is not a set", set_o);
PyStackRef_CLOSE(v);
ERROR_IF(true);
}
int err = _PySet_AddTakeRef((PySetObject *)set_o,
PyStackRef_AsPyObjectSteal(v));
ERROR_IF(err);
}
+14 -1
View File
@@ -1609,8 +1609,21 @@
oparg = CURRENT_OPARG();
v = stack_pointer[-1];
set = stack_pointer[-2 - (oparg-1)];
PyObject *set_o = PyStackRef_AsPyObjectBorrow(set);
if (!PySet_CheckExact(set_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyErr_Format(tstate, PyExc_TypeError,
"'%T' object is not a set", set_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_ERROR();
}
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _PySet_AddTakeRef((PySetObject *)PyStackRef_AsPyObjectBorrow(set),
int err = _PySet_AddTakeRef((PySetObject *)set_o,
PyStackRef_AsPyObjectSteal(v));
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err) {
+14 -1
View File
@@ -10859,8 +10859,21 @@
_PyStackRef v;
v = stack_pointer[-1];
set = stack_pointer[-2 - (oparg-1)];
PyObject *set_o = PyStackRef_AsPyObjectBorrow(set);
if (!PySet_CheckExact(set_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyErr_Format(tstate, PyExc_TypeError,
"'%T' object is not a set", set_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(error);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _PySet_AddTakeRef((PySetObject *)PyStackRef_AsPyObjectBorrow(set),
int err = _PySet_AddTakeRef((PySetObject *)set_o,
PyStackRef_AsPyObjectSteal(v));
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err) {