[3.9] bpo-11105: Do not crash when compiling recursive ASTs (GH-20594… · python/cpython@de58b31 (original) (raw)
`@@ -5,6 +5,7 @@
`
5
5
`import sys
`
6
6
``
7
7
`from argparse import ArgumentParser
`
``
8
`+
from contextlib import contextmanager
`
8
9
`from pathlib import Path
`
9
10
``
10
11
`import asdl
`
`@@ -394,6 +395,14 @@ def visitProduct(self, prod, name):
`
394
395
``
395
396
``
396
397
`class Obj2ModVisitor(PickleVisitor):
`
``
398
`+
@contextmanager
`
``
399
`+
def recursive_call(self, node, level):
`
``
400
`+
self.emit('if (Py_EnterRecursiveCall(" while traversing '%s' node")) {' % node, level, reflow=False)
`
``
401
`+
self.emit('goto failed;', level + 1)
`
``
402
`+
self.emit('}', level)
`
``
403
`+
yield
`
``
404
`+
self.emit('Py_LeaveRecursiveCall();', level)
`
``
405
+
397
406
`def funcHeader(self, name):
`
398
407
`ctype = get_c_type(name)
`
399
408
`self.emit("int", 0)
`
`@@ -568,8 +577,9 @@ def visitField(self, field, name, sum=None, prod=None, depth=0):
`
568
577
`self.emit("%s val;" % ctype, depth+2)
`
569
578
`self.emit("PyObject *tmp2 = PyList_GET_ITEM(tmp, i);", depth+2)
`
570
579
`self.emit("Py_INCREF(tmp2);", depth+2)
`
571
``
`-
self.emit("res = obj2ast_%s(state, tmp2, &val, arena);" %
`
572
``
`-
field.type, depth+2, reflow=False)
`
``
580
`+
with self.recursive_call(name, depth+2):
`
``
581
`+
self.emit("res = obj2ast_%s(state, tmp2, &val, arena);" %
`
``
582
`+
field.type, depth+2, reflow=False)
`
573
583
`self.emit("Py_DECREF(tmp2);", depth+2)
`
574
584
`self.emit("if (res != 0) goto failed;", depth+2)
`
575
585
`self.emit("if (len != PyList_GET_SIZE(tmp)) {", depth+2)
`
`@@ -582,8 +592,9 @@ def visitField(self, field, name, sum=None, prod=None, depth=0):
`
582
592
`self.emit("asdl_seq_SET(%s, i, val);" % field.name, depth+2)
`
583
593
`self.emit("}", depth+1)
`
584
594
`else:
`
585
``
`-
self.emit("res = obj2ast_%s(state, tmp, &%s, arena);" %
`
586
``
`-
(field.type, field.name), depth+1)
`
``
595
`+
with self.recursive_call(name, depth+1):
`
``
596
`+
self.emit("res = obj2ast_%s(state, tmp, &%s, arena);" %
`
``
597
`+
(field.type, field.name), depth+1)
`
587
598
`self.emit("if (res != 0) goto failed;", depth+1)
`
588
599
``
589
600
`self.emit("Py_CLEAR(tmp);", depth+1)
`