diff -r 4feb10457c13 Include/symtable.h --- a/Include/symtable.h Sun Aug 19 17:45:40 2012 -0400 +++ b/Include/symtable.h Mon Aug 20 00:34:36 2012 +0200 @@ -30,6 +30,7 @@ PyObject *st_private; /* name of current class or NULL */ PyFutureFeatures *st_future; /* module's future features that affect the symbol table */ + int recursion_limit; /* nesting limit. Fails when 0 is reached */ }; typedef struct _symtable_entry { diff -r 4feb10457c13 Lib/test/test_compile.py --- a/Lib/test/test_compile.py Sun Aug 19 17:45:40 2012 -0400 +++ b/Lib/test/test_compile.py Mon Aug 20 00:34:36 2012 +0200 @@ -474,6 +474,14 @@ self.assertInvalidSingle('f()\nxy # blah\nblah()') self.assertInvalidSingle('x = 5 # comment\nx = 6\n') + def test_compiler_recursion_limit(self): + self.assertRaises(RuntimeError, self.compile_single, "()" * 100000) + self.assertRaises(RuntimeError, self.compile_single, "a" + ".b" * 100000) + self.assertRaises(RuntimeError, self.compile_single, "a" + "[0]" * 100000) + self.compile_single("()" * 2000) + self.compile_single("a" + ".b" * 2000) + self.compile_single("a" + "[0]" * 2000) + def test_main(): support.run_unittest(TestSpecifics) diff -r 4feb10457c13 Python/symtable.c --- a/Python/symtable.c Sun Aug 19 17:45:40 2012 -0400 +++ b/Python/symtable.c Mon Aug 20 00:34:36 2012 +0200 @@ -218,17 +218,33 @@ return NULL; } +/* When compiling the use of C stack is probably going to be a lot + lighter than when executing Python code but still can overflow + and causing a Python crash if not checked (e.g. eval("()"*300000)). + Using the current recursion limit for the compiler too seems + overconstraining so a factor is used to allow deeper recursion + when compiling an expression. +*/ +#define COMPILER_STACK_FRAME_SCALE 4 + struct symtable * PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future) { struct symtable *st = symtable_new(); asdl_seq *seq; int i; + PyThreadState *tstate; if (st == NULL) return st; st->st_filename = filename; st->st_future = future; + + /* Setup recursion depth check counter */ + tstate = PyThreadState_GET(); + st->recursion_limit = ((Py_GetRecursionLimit() - tstate->recursion_depth) + * COMPILER_STACK_FRAME_SCALE); + /* Make the initial symbol information gathering pass */ if (!GET_IDENTIFIER(top) || !symtable_enter_block(st, top, ModuleBlock, (void *)mod, 0, 0)) { @@ -1268,6 +1284,12 @@ static int symtable_visit_expr(struct symtable *st, expr_ty e) { + if (--st->recursion_limit <= 0) { + PyErr_SetString(PyExc_RuntimeError, + "maximum recursion depth exceeded " + "while compiling an expression"); + return 0; + } switch (e->kind) { case BoolOp_kind: VISIT_SEQ(st, expr, e->v.BoolOp.values); @@ -1385,6 +1407,7 @@ VISIT_SEQ(st, expr, e->v.Tuple.elts); break; } + ++st->recursion_limit; return 1; }