From c0a18a62b39b00a414a461eadf380d0d989ebc4b Mon Sep 17 00:00:00 2001 From: AZero13 Date: Tue, 9 Dec 2025 09:22:43 -0500 Subject: [PATCH] gh-142462: Ensure kw_defaults is always populated in AST arguments Normalize AST arguments construction to always allocate kwonlyargs/kw_defaults (with length parity) and assert the invariant. --- ...025-12-09-09-22-38.gh-issue-142462.WlnNMW.rst | 2 ++ Parser/asdl_c.py | 16 ++++++++++++++++ Python/Python-ast.c | 13 +++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-09-09-22-38.gh-issue-142462.WlnNMW.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-09-09-22-38.gh-issue-142462.WlnNMW.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-09-09-22-38.gh-issue-142462.WlnNMW.rst new file mode 100644 index 00000000000000..faa957068ab2d2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-09-09-22-38.gh-issue-142462.WlnNMW.rst @@ -0,0 +1,2 @@ +Normalize AST arguments construction to always allocate +kwonlyargs/kw_defaults (with length parity) and assert the invariant. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index 3e252cbc4883d1..6a2d8de0270c13 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -437,6 +437,22 @@ def emit(s, depth=0, reflow=True): emit("p = (%s)_PyArena_Malloc(arena, sizeof(*p));" % ctype, 1); emit("if (!p)", 1) emit("return NULL;", 2) + # Special-case normalization for the arguments product to guarantee + # non-NULL kwonlyargs/kw_defaults with matched lengths. + if name == "arguments": + emit("if (kwonlyargs == NULL) {", 1) + emit("kwonlyargs = _Py_asdl_arg_seq_new(0, arena);", 2) + emit("if (!kwonlyargs) {", 2) + emit("return NULL;", 3) + emit("}", 2) + emit("}", 1) + emit("if (kw_defaults == NULL) {", 1) + emit("kw_defaults = _Py_asdl_expr_seq_new(asdl_seq_LEN(kwonlyargs), arena);", 2) + emit("if (!kw_defaults) {", 2) + emit("return NULL;", 3) + emit("}", 2) + emit("}", 1) + emit("assert(asdl_seq_LEN(kw_defaults) == asdl_seq_LEN(kwonlyargs));", 1) if union: self.emit_body_union(name, args, attrs) else: diff --git a/Python/Python-ast.c b/Python/Python-ast.c index aac24ed7d3c0c5..5a3f78b6462c26 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -8520,6 +8520,19 @@ _PyAST_arguments(asdl_arg_seq * posonlyargs, asdl_arg_seq * args, arg_ty p = (arguments_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; + if (kwonlyargs == NULL) { + kwonlyargs = _Py_asdl_arg_seq_new(0, arena); + if (!kwonlyargs) { + return NULL; + } + } + if (kw_defaults == NULL) { + kw_defaults = _Py_asdl_expr_seq_new(asdl_seq_LEN(kwonlyargs), arena); + if (!kw_defaults) { + return NULL; + } + } + assert(asdl_seq_LEN(kw_defaults) == asdl_seq_LEN(kwonlyargs)); p->posonlyargs = posonlyargs; p->args = args; p->vararg = vararg;