diff options
author | Batuhan Taskaya <batuhan@python.org> | 2021-06-03 20:01:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-03 20:01:02 (GMT) |
commit | f3491242e41933aa9529add7102edb68b80a25e9 (patch) | |
tree | cc4331ec55371585163e5db0291d6c17a765eca7 /Parser/asdl_c.py | |
parent | f461a7fc3f8740b9e79e8874175115a3474e5930 (diff) | |
download | cpython-f3491242e41933aa9529add7102edb68b80a25e9.zip cpython-f3491242e41933aa9529add7102edb68b80a25e9.tar.gz cpython-f3491242e41933aa9529add7102edb68b80a25e9.tar.bz2 |
bpo-11105: Do not crash when compiling recursive ASTs (GH-20594)
When compiling an AST object with a direct / indirect reference
cycles, on the conversion phase because of exceeding amount of
calls, a segfault was raised. This patch adds recursion guards to
places for preventing user inputs to not to crash AST but instead
raise a RecursionError.
Diffstat (limited to 'Parser/asdl_c.py')
-rwxr-xr-x | Parser/asdl_c.py | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index b71565c..4e5c5c8 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -6,6 +6,7 @@ import sys import textwrap from argparse import ArgumentParser +from contextlib import contextmanager from pathlib import Path import asdl @@ -421,6 +422,14 @@ class Obj2ModPrototypeVisitor(PickleVisitor): class Obj2ModVisitor(PickleVisitor): + @contextmanager + def recursive_call(self, node, level): + self.emit('if (Py_EnterRecursiveCall(" while traversing \'%s\' node")) {' % node, level, reflow=False) + self.emit('goto failed;', level + 1) + self.emit('}', level) + yield + self.emit('Py_LeaveRecursiveCall();', level) + def funcHeader(self, name): ctype = get_c_type(name) self.emit("int", 0) @@ -596,8 +605,9 @@ class Obj2ModVisitor(PickleVisitor): self.emit("%s val;" % ctype, depth+2) self.emit("PyObject *tmp2 = PyList_GET_ITEM(tmp, i);", depth+2) self.emit("Py_INCREF(tmp2);", depth+2) - self.emit("res = obj2ast_%s(state, tmp2, &val, arena);" % - field.type, depth+2, reflow=False) + with self.recursive_call(name, depth+2): + self.emit("res = obj2ast_%s(state, tmp2, &val, arena);" % + field.type, depth+2, reflow=False) self.emit("Py_DECREF(tmp2);", depth+2) self.emit("if (res != 0) goto failed;", depth+2) self.emit("if (len != PyList_GET_SIZE(tmp)) {", depth+2) @@ -610,8 +620,9 @@ class Obj2ModVisitor(PickleVisitor): self.emit("asdl_seq_SET(%s, i, val);" % field.name, depth+2) self.emit("}", depth+1) else: - self.emit("res = obj2ast_%s(state, tmp, &%s, arena);" % - (field.type, field.name), depth+1) + with self.recursive_call(name, depth+1): + self.emit("res = obj2ast_%s(state, tmp, &%s, arena);" % + (field.type, field.name), depth+1) self.emit("if (res != 0) goto failed;", depth+1) self.emit("Py_CLEAR(tmp);", depth+1) |