FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

[3.12] gh-116767: fix crash on 'async with' with many context managers (GH-118348) by iritkatriel · Pull Request #118477 · python/cpython · GitHub

/ cpython Public
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .c  (1) .h  (1) .py  (1) .rst  (1) All 4 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
2 changes: 1 addition & 1 deletion Include/cpython/code.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ struct PyCodeObject _PyCode_DEF(1);
*/
#define PY_PARSER_REQUIRES_FUTURE_KEYWORD

#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */
#define CO_MAXBLOCKS 21 /* Max static block nesting within a function */

PyAPI_DATA(PyTypeObject) PyCode_Type;

Expand Down
36 changes: 32 additions & 4 deletions Lib/test/test_syntax.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2269,13 +2269,40 @@ def bug():
code += "): yield a"
return code

CO_MAXBLOCKS = 20 # static nesting limit of the compiler
CO_MAXBLOCKS = 21 # static nesting limit of the compiler
MAX_MANAGERS = CO_MAXBLOCKS - 1 # One for the StopIteration block

for n in range(CO_MAXBLOCKS):
for n in range(MAX_MANAGERS):
with self.subTest(f"within range: {n=}"):
compile(get_code(n), "<string>", "exec")

for n in range(CO_MAXBLOCKS, CO_MAXBLOCKS + 5):
for n in range(MAX_MANAGERS, MAX_MANAGERS + 5):
with self.subTest(f"out of range: {n=}"):
self._check_error(get_code(n), "too many statically nested blocks")

@support.cpython_only
def test_async_with_statement_many_context_managers(self):
# See gh-116767

def get_code(n):
code = [ textwrap.dedent("""
async def bug():
async with (
a
""") ]
for i in range(n):
code.append(f" as a{i}, a\n")
code.append("): yield a")
return "".join(code)

CO_MAXBLOCKS = 21 # static nesting limit of the compiler
MAX_MANAGERS = CO_MAXBLOCKS - 1 # One for the StopIteration block

for n in range(MAX_MANAGERS):
with self.subTest(f"within range: {n=}"):
compile(get_code(n), "<string>", "exec")

for n in range(MAX_MANAGERS, MAX_MANAGERS + 5):
with self.subTest(f"out of range: {n=}"):
self._check_error(get_code(n), "too many statically nested blocks")

Expand Down Expand Up @@ -2407,7 +2434,8 @@ def test_syntax_error_on_deeply_nested_blocks(self):
while 20:
while 21:
while 22:
break
while 23:
break
"""
self._check_error(source, "too many statically nested blocks")

Expand Down
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix crash in compiler on 'async with' that has many context managers.
18 changes: 16 additions & 2 deletions Python/compile.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ compiler IR.

enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END,
WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER,
EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR };
EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR,
STOP_ITERATION };

struct fblockinfo {
enum fblocktype fb_type;
Expand Down Expand Up @@ -1546,6 +1547,7 @@ compiler_unwind_fblock(struct compiler *c, location *ploc,
case EXCEPTION_HANDLER:
case EXCEPTION_GROUP_HANDLER:
case ASYNC_COMPREHENSION_GENERATOR:
case STOP_ITERATION:
return SUCCESS;

case FOR_LOOP:
Expand Down Expand Up @@ -2235,14 +2237,26 @@ compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t f
c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args);
c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);

NEW_JUMP_TARGET_LABEL(c, start);
USE_LABEL(c, start);
bool add_stopiteration_handler = c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator;
if (add_stopiteration_handler) {
/* wrap_in_stopiteration_handler will push a block, so we need to account for that */
RETURN_IF_ERROR(
compiler_push_fblock(c, NO_LOCATION, STOP_ITERATION,
start, NO_LABEL, NULL));
}

for (Py_ssize_t i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) {
VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i));
}
if (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator) {
if (add_stopiteration_handler) {
if (wrap_in_stopiteration_handler(c) < 0) {
compiler_exit_scope(c);
return ERROR;
}
compiler_pop_fblock(c, STOP_ITERATION, start);
}
PyCodeObject *co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);
Expand Down

Back | FazBrowse Home | New Git URL