From 932822cbc998c16616f33078b421373a53ced4d0 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 28 Aug 2026 19:10:37 +0100 Subject: [PATCH 1/2] gh-156525: fix a few error path scope management bugs in symtable (#156526) --- Python/symtable.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c index e3e89ab403a607e..8da04b40e8ad142 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1455,6 +1455,7 @@ symtable_enter_existing_block(struct symtable *st, PySTEntryObject* ste, bool ad if (add_to_children && prev) { if (PyList_Append(prev->ste_children, (PyObject *)ste) < 0) { + symtable_exit_block(st); return 0; } } @@ -1466,21 +1467,27 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, void *ast, _Py_SourceLocation loc) { PySTEntryObject *ste = ste_new(st, name, block, ast, loc); - if (ste == NULL) + if (ste == NULL) { return 0; + } int result = symtable_enter_existing_block(st, ste, /* add_to_children */true); Py_DECREF(ste); + if (result == 0) { + return 0; + } if (block == AnnotationBlock || block == TypeVariableBlock || block == TypeAliasBlock) { _Py_DECLARE_STR(format, ".format"); // We need to insert code that reads this "parameter" to the function. if (!symtable_add_def(st, &_Py_STR(format), DEF_PARAM, loc)) { + symtable_exit_block(st); return 0; } if (!symtable_add_def(st, &_Py_STR(format), USE, loc)) { + symtable_exit_block(st); return 0; } } - return result; + return 1; } static long @@ -1676,7 +1683,7 @@ symtable_enter_type_param_block(struct symtable *st, identifier name, if (current_type == ClassBlock) { st->st_cur->ste_can_see_class_scope = 1; if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, loc)) { - return 0; + goto error; } } if (kind == ClassDef_kind) { @@ -1684,33 +1691,36 @@ symtable_enter_type_param_block(struct symtable *st, identifier name, // It gets "set" when we create the type params tuple and // "used" when we build up the bases. if (!symtable_add_def(st, &_Py_STR(type_params), DEF_LOCAL, loc)) { - return 0; + goto error; } if (!symtable_add_def(st, &_Py_STR(type_params), USE, loc)) { - return 0; + goto error; } // This is used for setting the generic base _Py_DECLARE_STR(generic_base, ".generic_base"); if (!symtable_add_def(st, &_Py_STR(generic_base), DEF_LOCAL, loc)) { - return 0; + goto error; } if (!symtable_add_def(st, &_Py_STR(generic_base), USE, loc)) { - return 0; + goto error; } } if (has_defaults) { _Py_DECLARE_STR(defaults, ".defaults"); if (!symtable_add_def(st, &_Py_STR(defaults), DEF_PARAM, loc)) { - return 0; + goto error; } } if (has_kwdefaults) { _Py_DECLARE_STR(kwdefaults, ".kwdefaults"); if (!symtable_add_def(st, &_Py_STR(kwdefaults), DEF_PARAM, loc)) { - return 0; + goto error; } } return 1; +error: + symtable_exit_block(st); + return 0; } /* VISIT, VISIT_SEQ and VISIT_SEQ_TAIL take an ASDL type as their second argument. From 683ef4082d374eb26c1ead33f8fd989eeadc742d Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 28 Aug 2026 22:01:47 +0100 Subject: [PATCH 2/2] gh-156466: fix cleanup on error in codegen_class_body (#156507) --- Python/codegen.c | 50 +++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/Python/codegen.c b/Python/codegen.c index 17901cbc1bf976e..b3e9488b0236fbb 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -310,19 +310,23 @@ codegen_addop_load_const(compiler *c, location loc, PyObject *o) #define ADDOP_LOAD_CONST_IN_SCOPE(C, LOC, O) \ RETURN_IF_ERROR_IN_SCOPE((C), codegen_addop_load_const((C), (LOC), (O))) +static int +codegen_addop_load_const_new(compiler *c, location loc, PyObject *o) +{ + if (o == NULL) { + return ERROR; + } + int ret = codegen_addop_load_const(c, loc, o); + Py_DECREF(o); + return ret; +} + /* Same as ADDOP_LOAD_CONST, but steals a reference. */ -#define ADDOP_LOAD_CONST_NEW(C, LOC, O) \ - do { \ - PyObject *__new_const = (O); \ - if (__new_const == NULL) { \ - return ERROR; \ - } \ - if (codegen_addop_load_const((C), (LOC), __new_const) < 0) { \ - Py_DECREF(__new_const); \ - return ERROR; \ - } \ - Py_DECREF(__new_const); \ - } while (0) +#define ADDOP_LOAD_CONST_NEW(C, LOC, O) \ + RETURN_IF_ERROR(codegen_addop_load_const_new((C), (LOC), (O))) + +#define ADDOP_LOAD_CONST_NEW_IN_SCOPE(C, LOC, O) \ + RETURN_IF_ERROR_IN_SCOPE((C), codegen_addop_load_const_new((C), (LOC), (O))) static int codegen_addop_o(compiler *c, location loc, @@ -1613,16 +1617,16 @@ codegen_class_body(compiler *c, stmt_ty s, int firstlineno) RETURN_IF_ERROR_IN_SCOPE(c, codegen_nameop(c, loc, &_Py_ID(__name__), Load)); /* ... and store it as __module__ */ RETURN_IF_ERROR_IN_SCOPE(c, codegen_nameop(c, loc, &_Py_ID(__module__), Store)); - ADDOP_LOAD_CONST(c, loc, QUALNAME(c)); + ADDOP_LOAD_CONST_IN_SCOPE(c, loc, QUALNAME(c)); RETURN_IF_ERROR_IN_SCOPE(c, codegen_nameop(c, loc, &_Py_ID(__qualname__), Store)); - ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromLong(METADATA(c)->u_firstlineno)); + ADDOP_LOAD_CONST_NEW_IN_SCOPE(c, loc, PyLong_FromLong(METADATA(c)->u_firstlineno)); RETURN_IF_ERROR_IN_SCOPE(c, codegen_nameop(c, loc, &_Py_ID(__firstlineno__), Store)); asdl_type_param_seq *type_params = s->v.ClassDef.type_params; if (asdl_seq_LEN(type_params) > 0) { RETURN_IF_ERROR_IN_SCOPE(c, codegen_set_type_params_in_class(c, loc)); } if (SYMTABLE_ENTRY(c)->ste_needs_classdict) { - ADDOP(c, loc, LOAD_LOCALS); + ADDOP_IN_SCOPE(c, loc, LOAD_LOCALS); // We can't use codegen_nameop here because we need to generate a // STORE_DEREF in a class namespace, and codegen_nameop() won't do @@ -1635,13 +1639,7 @@ codegen_class_body(compiler *c, stmt_ty s, int firstlineno) } /* compile the body proper */ RETURN_IF_ERROR_IN_SCOPE(c, codegen_body(c, loc, s->v.ClassDef.body, false)); - PyObject *static_attributes = _PyCompile_StaticAttributesAsTuple(c); - if (static_attributes == NULL) { - _PyCompile_ExitScope(c); - return ERROR; - } - ADDOP_LOAD_CONST(c, NO_LOCATION, static_attributes); - Py_CLEAR(static_attributes); + ADDOP_LOAD_CONST_NEW_IN_SCOPE(c, NO_LOCATION, _PyCompile_StaticAttributesAsTuple(c)); RETURN_IF_ERROR_IN_SCOPE( c, codegen_nameop(c, NO_LOCATION, &_Py_ID(__static_attributes__), Store)); /* The following code is artificial */ @@ -1650,7 +1648,7 @@ codegen_class_body(compiler *c, stmt_ty s, int firstlineno) /* Store __classdictcell__ into class namespace */ int i = _PyCompile_LookupCellvar(c, &_Py_ID(__classdict__)); RETURN_IF_ERROR_IN_SCOPE(c, i); - ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); + ADDOP_I_IN_SCOPE(c, NO_LOCATION, LOAD_CLOSURE, i); RETURN_IF_ERROR_IN_SCOPE( c, codegen_nameop(c, NO_LOCATION, &_Py_ID(__classdictcell__), Store)); } @@ -1659,14 +1657,14 @@ codegen_class_body(compiler *c, stmt_ty s, int firstlineno) /* Store __classcell__ into class namespace & return it */ int i = _PyCompile_LookupCellvar(c, &_Py_ID(__class__)); RETURN_IF_ERROR_IN_SCOPE(c, i); - ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); - ADDOP_I(c, NO_LOCATION, COPY, 1); + ADDOP_I_IN_SCOPE(c, NO_LOCATION, LOAD_CLOSURE, i); + ADDOP_I_IN_SCOPE(c, NO_LOCATION, COPY, 1); RETURN_IF_ERROR_IN_SCOPE( c, codegen_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store)); } else { /* No methods referenced __class__, so just return None */ - ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + ADDOP_LOAD_CONST_IN_SCOPE(c, NO_LOCATION, Py_None); } ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE); /* create the code object */