bpo-11105: Do not crash when compiling recursive ASTs (GH-20594) · python/cpython@f349124 (original) (raw)
`@@ -6,6 +6,7 @@
`
6
6
`import textwrap
`
7
7
``
8
8
`from argparse import ArgumentParser
`
``
9
`+
from contextlib import contextmanager
`
9
10
`from pathlib import Path
`
10
11
``
11
12
`import asdl
`
`@@ -421,6 +422,14 @@ def visitProduct(self, prod, name):
`
421
422
``
422
423
``
423
424
`class Obj2ModVisitor(PickleVisitor):
`
``
425
`+
@contextmanager
`
``
426
`+
def recursive_call(self, node, level):
`
``
427
`+
self.emit('if (Py_EnterRecursiveCall(" while traversing '%s' node")) {' % node, level, reflow=False)
`
``
428
`+
self.emit('goto failed;', level + 1)
`
``
429
`+
self.emit('}', level)
`
``
430
`+
yield
`
``
431
`+
self.emit('Py_LeaveRecursiveCall();', level)
`
``
432
+
424
433
`def funcHeader(self, name):
`
425
434
`ctype = get_c_type(name)
`
426
435
`self.emit("int", 0)
`
`@@ -596,8 +605,9 @@ def visitField(self, field, name, sum=None, prod=None, depth=0):
`
596
605
`self.emit("%s val;" % ctype, depth+2)
`
597
606
`self.emit("PyObject *tmp2 = PyList_GET_ITEM(tmp, i);", depth+2)
`
598
607
`self.emit("Py_INCREF(tmp2);", depth+2)
`
599
``
`-
self.emit("res = obj2ast_%s(state, tmp2, &val, arena);" %
`
600
``
`-
field.type, depth+2, reflow=False)
`
``
608
`+
with self.recursive_call(name, depth+2):
`
``
609
`+
self.emit("res = obj2ast_%s(state, tmp2, &val, arena);" %
`
``
610
`+
field.type, depth+2, reflow=False)
`
601
611
`self.emit("Py_DECREF(tmp2);", depth+2)
`
602
612
`self.emit("if (res != 0) goto failed;", depth+2)
`
603
613
`self.emit("if (len != PyList_GET_SIZE(tmp)) {", depth+2)
`
`@@ -610,8 +620,9 @@ def visitField(self, field, name, sum=None, prod=None, depth=0):
`
610
620
`self.emit("asdl_seq_SET(%s, i, val);" % field.name, depth+2)
`
611
621
`self.emit("}", depth+1)
`
612
622
`else:
`
613
``
`-
self.emit("res = obj2ast_%s(state, tmp, &%s, arena);" %
`
614
``
`-
(field.type, field.name), depth+1)
`
``
623
`+
with self.recursive_call(name, depth+1):
`
``
624
`+
self.emit("res = obj2ast_%s(state, tmp, &%s, arena);" %
`
``
625
`+
(field.type, field.name), depth+1)
`
615
626
`self.emit("if (res != 0) goto failed;", depth+1)
`
616
627
``
617
628
`self.emit("Py_CLEAR(tmp);", depth+1)
`