From a8c0c60020bbfecc72afde734db975279b3c2784 Mon Sep 17 00:00:00 2001 From: A0su Date: Fri, 3 Apr 2026 00:22:20 -0500 Subject: [PATCH 1/3] refactor codegen_deferred_annotations_body to ensure mangled is decref'd on error --- Python/codegen.c | 69 +++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/Python/codegen.c b/Python/codegen.c index aca590d055f466..3765dbc351af93 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -777,6 +777,41 @@ codegen_leave_annotations_scope(compiler *c, location loc) return SUCCESS; } +static int +codegen_deferred_annotations_entry(compiler *c, location loc, + PyObject *conditional_annotation_indices, int scope_type, stmt_ty st, PyObject *mangled, Py_ssize_t i) +{ + PyObject *cond_index = PyList_GET_ITEM(conditional_annotation_indices, i); + assert(PyLong_CheckExact(cond_index)); + long idx = PyLong_AS_LONG(cond_index); + NEW_JUMP_TARGET_LABEL(c, not_set); + + if (idx != -1) { + ADDOP_LOAD_CONST(c, LOC(st), cond_index); + if (scope_type == COMPILE_SCOPE_CLASS) { + ADDOP_NAME( + c, LOC(st), LOAD_DEREF, &_Py_ID(__conditional_annotations__), freevars); + } + else { + ADDOP_NAME( + c, LOC(st), LOAD_GLOBAL, &_Py_ID(__conditional_annotations__), names); + } + + ADDOP_I(c, LOC(st), CONTAINS_OP, 0); + ADDOP_JUMP(c, LOC(st), POP_JUMP_IF_FALSE, not_set); + } + + VISIT(c, expr, st->v.AnnAssign.annotation); + ADDOP_I(c, LOC(st), COPY, 2); + ADDOP_LOAD_CONST(c, LOC(st), mangled); + // stack now contains + ADDOP(c, loc, STORE_SUBSCR); + // stack now contains + + USE_LABEL(c, not_set); + return SUCCESS; +} + static int codegen_deferred_annotations_body(compiler *c, location loc, PyObject *deferred_anno, PyObject *conditional_annotation_indices, int scope_type) @@ -798,37 +833,11 @@ codegen_deferred_annotations_body(compiler *c, location loc, if (!mangled) { return ERROR; } - // NOTE: ref of mangled can be leaked on ADDOP* and VISIT macros due to early returns - // fixing would require an overhaul of these macros - - PyObject *cond_index = PyList_GET_ITEM(conditional_annotation_indices, i); - assert(PyLong_CheckExact(cond_index)); - long idx = PyLong_AS_LONG(cond_index); - NEW_JUMP_TARGET_LABEL(c, not_set); - - if (idx != -1) { - ADDOP_LOAD_CONST(c, LOC(st), cond_index); - if (scope_type == COMPILE_SCOPE_CLASS) { - ADDOP_NAME( - c, LOC(st), LOAD_DEREF, &_Py_ID(__conditional_annotations__), freevars); - } - else { - ADDOP_NAME( - c, LOC(st), LOAD_GLOBAL, &_Py_ID(__conditional_annotations__), names); - } - ADDOP_I(c, LOC(st), CONTAINS_OP, 0); - ADDOP_JUMP(c, LOC(st), POP_JUMP_IF_FALSE, not_set); - } - - VISIT(c, expr, st->v.AnnAssign.annotation); - ADDOP_I(c, LOC(st), COPY, 2); - ADDOP_LOAD_CONST_NEW(c, LOC(st), mangled); - // stack now contains - ADDOP(c, loc, STORE_SUBSCR); - // stack now contains - - USE_LABEL(c, not_set); + int ret = codegen_deferred_annotations_entry(c, loc, conditional_annotation_indices, + scope_type, st, mangled, i); + Py_DECREF(mangled); + RETURN_IF_ERROR(ret); } return SUCCESS; } From 491bf1cd6ef8bf6b50393318c18bd25f3ab650d8 Mon Sep 17 00:00:00 2001 From: A0su Date: Fri, 3 Apr 2026 17:03:39 -0500 Subject: [PATCH 2/3] refactor func signature down --- Python/codegen.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Python/codegen.c b/Python/codegen.c index 3765dbc351af93..6df9a73f5f7df0 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -778,11 +778,8 @@ codegen_leave_annotations_scope(compiler *c, location loc) } static int -codegen_deferred_annotations_entry(compiler *c, location loc, - PyObject *conditional_annotation_indices, int scope_type, stmt_ty st, PyObject *mangled, Py_ssize_t i) +codegen_deferred_annotations_entry(compiler *c, location loc, int scope_type, stmt_ty st, PyObject *mangled, PyObject *cond_index) { - PyObject *cond_index = PyList_GET_ITEM(conditional_annotation_indices, i); - assert(PyLong_CheckExact(cond_index)); long idx = PyLong_AS_LONG(cond_index); NEW_JUMP_TARGET_LABEL(c, not_set); @@ -829,13 +826,16 @@ codegen_deferred_annotations_body(compiler *c, location loc, if (st == NULL) { return ERROR; } + + PyObject *cond_index = PyList_GET_ITEM(conditional_annotation_indices, i); + assert(PyLong_CheckExact(cond_index)); + PyObject *mangled = _PyCompile_Mangle(c, st->v.AnnAssign.target->v.Name.id); if (!mangled) { return ERROR; } - int ret = codegen_deferred_annotations_entry(c, loc, conditional_annotation_indices, - scope_type, st, mangled, i); + int ret = codegen_deferred_annotations_entry(c, loc, scope_type, st, mangled, cond_index); Py_DECREF(mangled); RETURN_IF_ERROR(ret); } From 9a44ccf76c095be744e505eb2416cd9aa59fa8a9 Mon Sep 17 00:00:00 2001 From: A0su Date: Fri, 3 Apr 2026 17:14:15 -0500 Subject: [PATCH 3/3] add blurb --- .../2026-04-03-17-13-51.gh-issue-148059.-WQMGn.rst | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-03-17-13-51.gh-issue-148059.-WQMGn.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-03-17-13-51.gh-issue-148059.-WQMGn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-03-17-13-51.gh-issue-148059.-WQMGn.rst new file mode 100644 index 00000000000000..335bf0dbfdda09 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-03-17-13-51.gh-issue-148059.-WQMGn.rst @@ -0,0 +1,5 @@ +For codegen method ``codegen_deferred_annotations_body`` we can fail to +decref ``mangled`` during the generation of the bytecode for an annotation +entry. This change creates a subfunction for the bytecode generation of the +annotation entry which will also to decref ``mangled`` in the event of +errors.