[3.12] gh-116767: fix crash on 'async with' with many context managers (GH-118348) (#118477)

gh-116767: fix crash on 'async with' with many context managers (GH-118348)

Account for `add_stopiteration_handler` pushing a block for `async with`.
To allow generator functions that previously almost hit the `CO_MAXBLOCKS`
limit by nesting non-async blocks, the limit is increased by 1.
This increase allows one more block in non-generator functions.

(cherry picked from commit c1bf4874c1)
This commit is contained in:
Irit Katriel 2024-05-01 18:23:29 +01:00 committed by GitHub
parent f5406ef454
commit ebef3c5ba4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 50 additions and 7 deletions

View file

@ -2269,13 +2269,40 @@ if x:
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")
@ -2407,7 +2434,8 @@ while 1:
while 20:
while 21:
while 22:
break
while 23:
break
"""
self._check_error(source, "too many statically nested blocks")