Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e69bfc3

Browse files
committed
Issue #5765: Merge from 3.3
2 parents c992faf + aab9c2b commit e69bfc3

7 files changed

Lines changed: 108 additions & 44 deletions

File tree

Include/symtable.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ struct symtable {
3030
PyObject *st_private; /* name of current class or NULL */
3131
PyFutureFeatures *st_future; /* module's future features that affect
3232
the symbol table */
33+
int recursion_depth; /* current recursion depth */
34+
int recursion_limit; /* recursion limit */
3335
};
3436

3537
typedef struct _symtable_entry {

Lib/test/crashers/compiler_recursion.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

Lib/test/test_compile.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,33 @@ def test_bad_single_statement(self):
474474
self.assertInvalidSingle('f()\nxy # blah\nblah()')
475475
self.assertInvalidSingle('x = 5 # comment\nx = 6\n')
476476

477+
@support.cpython_only
478+
def test_compiler_recursion_limit(self):
479+
# Expected limit is sys.getrecursionlimit() * the scaling factor
480+
# in symtable.c (currently 3)
481+
# We expect to fail *at* that limit, because we use up some of
482+
# the stack depth limit in the test suite code
483+
# So we check the expected limit and 75% of that
484+
# XXX (ncoghlan): duplicating the scaling factor here is a little
485+
# ugly. Perhaps it should be exposed somewhere...
486+
fail_depth = sys.getrecursionlimit() * 3
487+
success_depth = int(fail_depth * 0.75)
488+
489+
def check_limit(prefix, repeated):
490+
expect_ok = prefix + repeated * success_depth
491+
self.compile_single(expect_ok)
492+
broken = prefix + repeated * fail_depth
493+
details = "Compiling ({!r} + {!r} * {})".format(
494+
prefix, repeated, fail_depth)
495+
with self.assertRaises(RuntimeError, msg=details):
496+
self.compile_single(broken)
497+
498+
check_limit("a", "()")
499+
check_limit("a", ".b")
500+
check_limit("a", "[0]")
501+
check_limit("a", "*a")
502+
503+
477504
def test_main():
478505
support.run_unittest(TestSpecifics)
479506

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ Hans de Graaff
431431
Nathaniel Gray
432432
Eddy De Greef
433433
Grant Griffin
434+
Andrea Griffini
434435
Duncan Grisby
435436
Fabian Groffen
436437
Eric Groo

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #5765: Apply a hard recursion limit in the compiler instead of
14+
blowing the stack and segfaulting.
15+
1316
- Issue #16402: When slicing a range, fix shadowing of exceptions from
1417
__index__.
1518

Python/compile.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ struct compiler_unit {
141141
The u pointer points to the current compilation unit, while units
142142
for enclosing blocks are stored in c_stack. The u and c_stack are
143143
managed by compiler_enter_scope() and compiler_exit_scope().
144+
145+
Note that we don't track recursion levels during compilation - the
146+
task of detecting and rejecting excessive levels of nesting is
147+
handled by the symbol analysis pass.
148+
144149
*/
145150

146151
struct compiler {

Python/symtable.c

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,40 @@ symtable_new(void)
223223
return NULL;
224224
}
225225

226+
/* When compiling the use of C stack is probably going to be a lot
227+
lighter than when executing Python code but still can overflow
228+
and causing a Python crash if not checked (e.g. eval("()"*300000)).
229+
Using the current recursion limit for the compiler seems too
230+
restrictive (it caused at least one test to fail) so a factor is
231+
used to allow deeper recursion when compiling an expression.
232+
233+
Using a scaling factor means this should automatically adjust when
234+
the recursion limit is adjusted for small or large C stack allocations.
235+
*/
236+
#define COMPILER_STACK_FRAME_SCALE 3
237+
226238
struct symtable *
227239
PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future)
228240
{
229241
struct symtable *st = symtable_new();
230242
asdl_seq *seq;
231243
int i;
244+
PyThreadState *tstate;
232245

233246
if (st == NULL)
234247
return st;
235248
st->st_filename = filename;
236249
st->st_future = future;
250+
251+
/* Setup recursion depth check counters */
252+
tstate = PyThreadState_GET();
253+
if (!tstate) {
254+
PySymtable_Free(st);
255+
return NULL;
256+
}
257+
st->recursion_depth = tstate->recursion_depth * COMPILER_STACK_FRAME_SCALE;
258+
st->recursion_limit = Py_GetRecursionLimit() * COMPILER_STACK_FRAME_SCALE;
259+
237260
/* Make the initial symbol information gathering pass */
238261
if (!GET_IDENTIFIER(top) ||
239262
!symtable_enter_block(st, top, ModuleBlock, (void *)mod, 0, 0)) {
@@ -1031,19 +1054,25 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag)
10311054
10321055
VISIT_SEQ_TAIL permits the start of an ASDL sequence to be skipped, which is
10331056
useful if the first node in the sequence requires special treatment.
1057+
1058+
VISIT_QUIT macro returns the specified value exiting from the function but
1059+
first adjusts current recursion counter depth.
10341060
*/
10351061

1062+
#define VISIT_QUIT(ST, X) \
1063+
return --(ST)->recursion_depth,(X)
1064+
10361065
#define VISIT(ST, TYPE, V) \
10371066
if (!symtable_visit_ ## TYPE((ST), (V))) \
1038-
return 0;
1067+
VISIT_QUIT((ST), 0);
10391068

10401069
#define VISIT_SEQ(ST, TYPE, SEQ) { \
10411070
int i; \
10421071
asdl_seq *seq = (SEQ); /* avoid variable capture */ \
10431072
for (i = 0; i < asdl_seq_LEN(seq); i++) { \
10441073
TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
10451074
if (!symtable_visit_ ## TYPE((ST), elt)) \
1046-
return 0; \
1075+
VISIT_QUIT((ST), 0); \
10471076
} \
10481077
}
10491078

@@ -1053,7 +1082,7 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag)
10531082
for (i = (START); i < asdl_seq_LEN(seq); i++) { \
10541083
TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
10551084
if (!symtable_visit_ ## TYPE((ST), elt)) \
1056-
return 0; \
1085+
VISIT_QUIT((ST), 0); \
10571086
} \
10581087
}
10591088

@@ -1064,7 +1093,7 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag)
10641093
expr_ty elt = (expr_ty)asdl_seq_GET(seq, i); \
10651094
if (!elt) continue; /* can be NULL */ \
10661095
if (!symtable_visit_expr((ST), elt)) \
1067-
return 0; \
1096+
VISIT_QUIT((ST), 0); \
10681097
} \
10691098
}
10701099

@@ -1108,32 +1137,37 @@ symtable_record_directive(struct symtable *st, identifier name, stmt_ty s)
11081137
static int
11091138
symtable_visit_stmt(struct symtable *st, stmt_ty s)
11101139
{
1140+
if (++st->recursion_depth > st->recursion_limit) {
1141+
PyErr_SetString(PyExc_RuntimeError,
1142+
"maximum recursion depth exceeded during compilation");
1143+
VISIT_QUIT(st, 0);
1144+
}
11111145
switch (s->kind) {
11121146
case FunctionDef_kind:
11131147
if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL))
1114-
return 0;
1148+
VISIT_QUIT(st, 0);
11151149
if (s->v.FunctionDef.args->defaults)
11161150
VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults);
11171151
if (s->v.FunctionDef.args->kw_defaults)
11181152
VISIT_KWONLYDEFAULTS(st,
11191153
s->v.FunctionDef.args->kw_defaults);
11201154
if (!symtable_visit_annotations(st, s))
1121-
return 0;
1155+
VISIT_QUIT(st, 0);
11221156
if (s->v.FunctionDef.decorator_list)
11231157
VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list);
11241158
if (!symtable_enter_block(st, s->v.FunctionDef.name,
11251159
FunctionBlock, (void *)s, s->lineno,
11261160
s->col_offset))
1127-
return 0;
1161+
VISIT_QUIT(st, 0);
11281162
VISIT(st, arguments, s->v.FunctionDef.args);
11291163
VISIT_SEQ(st, stmt, s->v.FunctionDef.body);
11301164
if (!symtable_exit_block(st, s))
1131-
return 0;
1165+
VISIT_QUIT(st, 0);
11321166
break;
11331167
case ClassDef_kind: {
11341168
PyObject *tmp;
11351169
if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL))
1136-
return 0;
1170+
VISIT_QUIT(st, 0);
11371171
VISIT_SEQ(st, expr, s->v.ClassDef.bases);
11381172
VISIT_SEQ(st, keyword, s->v.ClassDef.keywords);
11391173
if (s->v.ClassDef.starargs)
@@ -1144,20 +1178,20 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
11441178
VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list);
11451179
if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
11461180
(void *)s, s->lineno, s->col_offset))
1147-
return 0;
1181+
VISIT_QUIT(st, 0);
11481182
if (!GET_IDENTIFIER(__class__) ||
11491183
!symtable_add_def(st, __class__, DEF_LOCAL) ||
11501184
!GET_IDENTIFIER(__locals__) ||
11511185
!symtable_add_def(st, __locals__, DEF_PARAM)) {
11521186
symtable_exit_block(st, s);
1153-
return 0;
1187+
VISIT_QUIT(st, 0);
11541188
}
11551189
tmp = st->st_private;
11561190
st->st_private = s->v.ClassDef.name;
11571191
VISIT_SEQ(st, stmt, s->v.ClassDef.body);
11581192
st->st_private = tmp;
11591193
if (!symtable_exit_block(st, s))
1160-
return 0;
1194+
VISIT_QUIT(st, 0);
11611195
break;
11621196
}
11631197
case Return_kind:
@@ -1241,7 +1275,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
12411275
identifier name = (identifier)asdl_seq_GET(seq, i);
12421276
long cur = symtable_lookup(st, name);
12431277
if (cur < 0)
1244-
return 0;
1278+
VISIT_QUIT(st, 0);
12451279
if (cur & (DEF_LOCAL | USE)) {
12461280
char buf[256];
12471281
char *c_name = _PyUnicode_AsString(name);
@@ -1256,12 +1290,12 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
12561290
GLOBAL_AFTER_USE,
12571291
c_name);
12581292
if (!symtable_warn(st, buf, s->lineno))
1259-
return 0;
1293+
VISIT_QUIT(st, 0);
12601294
}
12611295
if (!symtable_add_def(st, name, DEF_GLOBAL))
1262-
return 0;
1296+
VISIT_QUIT(st, 0);
12631297
if (!symtable_record_directive(st, name, s))
1264-
return 0;
1298+
VISIT_QUIT(st, 0);
12651299
}
12661300
break;
12671301
}
@@ -1272,7 +1306,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
12721306
identifier name = (identifier)asdl_seq_GET(seq, i);
12731307
long cur = symtable_lookup(st, name);
12741308
if (cur < 0)
1275-
return 0;
1309+
VISIT_QUIT(st, 0);
12761310
if (cur & (DEF_LOCAL | USE)) {
12771311
char buf[256];
12781312
char *c_name = _PyUnicode_AsString(name);
@@ -1287,12 +1321,12 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
12871321
NONLOCAL_AFTER_USE,
12881322
c_name);
12891323
if (!symtable_warn(st, buf, s->lineno))
1290-
return 0;
1324+
VISIT_QUIT(st, 0);
12911325
}
12921326
if (!symtable_add_def(st, name, DEF_NONLOCAL))
1293-
return 0;
1327+
VISIT_QUIT(st, 0);
12941328
if (!symtable_record_directive(st, name, s))
1295-
return 0;
1329+
VISIT_QUIT(st, 0);
12961330
}
12971331
break;
12981332
}
@@ -1309,12 +1343,17 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
13091343
VISIT_SEQ(st, stmt, s->v.With.body);
13101344
break;
13111345
}
1312-
return 1;
1346+
VISIT_QUIT(st, 1);
13131347
}
13141348

13151349
static int
13161350
symtable_visit_expr(struct symtable *st, expr_ty e)
13171351
{
1352+
if (++st->recursion_depth > st->recursion_limit) {
1353+
PyErr_SetString(PyExc_RuntimeError,
1354+
"maximum recursion depth exceeded during compilation");
1355+
VISIT_QUIT(st, 0);
1356+
}
13181357
switch (e->kind) {
13191358
case BoolOp_kind:
13201359
VISIT_SEQ(st, expr, e->v.BoolOp.values);
@@ -1328,7 +1367,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
13281367
break;
13291368
case Lambda_kind: {
13301369
if (!GET_IDENTIFIER(lambda))
1331-
return 0;
1370+
VISIT_QUIT(st, 0);
13321371
if (e->v.Lambda.args->defaults)
13331372
VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
13341373
if (e->v.Lambda.args->kw_defaults)
@@ -1337,11 +1376,11 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
13371376
if (!symtable_enter_block(st, lambda,
13381377
FunctionBlock, (void *)e, e->lineno,
13391378
e->col_offset))
1340-
return 0;
1379+
VISIT_QUIT(st, 0);
13411380
VISIT(st, arguments, e->v.Lambda.args);
13421381
VISIT(st, expr, e->v.Lambda.body);
13431382
if (!symtable_exit_block(st, (void *)e))
1344-
return 0;
1383+
VISIT_QUIT(st, 0);
13451384
break;
13461385
}
13471386
case IfExp_kind:
@@ -1358,19 +1397,19 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
13581397
break;
13591398
case GeneratorExp_kind:
13601399
if (!symtable_visit_genexp(st, e))
1361-
return 0;
1400+
VISIT_QUIT(st, 0);
13621401
break;
13631402
case ListComp_kind:
13641403
if (!symtable_visit_listcomp(st, e))
1365-
return 0;
1404+
VISIT_QUIT(st, 0);
13661405
break;
13671406
case SetComp_kind:
13681407
if (!symtable_visit_setcomp(st, e))
1369-
return 0;
1408+
VISIT_QUIT(st, 0);
13701409
break;
13711410
case DictComp_kind:
13721411
if (!symtable_visit_dictcomp(st, e))
1373-
return 0;
1412+
VISIT_QUIT(st, 0);
13741413
break;
13751414
case Yield_kind:
13761415
case YieldFrom_kind: {
@@ -1414,14 +1453,14 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
14141453
case Name_kind:
14151454
if (!symtable_add_def(st, e->v.Name.id,
14161455
e->v.Name.ctx == Load ? USE : DEF_LOCAL))
1417-
return 0;
1456+
VISIT_QUIT(st, 0);
14181457
/* Special-case super: it counts as a use of __class__ */
14191458
if (e->v.Name.ctx == Load &&
14201459
st->st_cur->ste_type == FunctionBlock &&
14211460
!PyUnicode_CompareWithASCIIString(e->v.Name.id, "super")) {
14221461
if (!GET_IDENTIFIER(__class__) ||
14231462
!symtable_add_def(st, __class__, USE))
1424-
return 0;
1463+
VISIT_QUIT(st, 0);
14251464
}
14261465
break;
14271466
/* child nodes of List and Tuple will have expr_context set */
@@ -1432,7 +1471,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
14321471
VISIT_SEQ(st, expr, e->v.Tuple.elts);
14331472
break;
14341473
}
1435-
return 1;
1474+
VISIT_QUIT(st, 1);
14361475
}
14371476

14381477
static int

0 commit comments

Comments
 (0)