summaryrefslogtreecommitdiffstats
path: root/Python/symtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/symtable.c')
-rw-r--r--Python/symtable.c267
1 files changed, 133 insertions, 134 deletions
diff --git a/Python/symtable.c b/Python/symtable.c
index 35fc6e1..55898f9 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -19,10 +19,6 @@
#define IMPORT_STAR_WARNING "import * only allowed at module level"
-#define RETURN_VAL_IN_GENERATOR \
- "'return' with argument inside generator"
-
-
static PySTEntryObject *
ste_new(struct symtable *st, identifier name, _Py_block_ty block,
void *key, int lineno, int col_offset)
@@ -187,6 +183,7 @@ static int symtable_visit_params(struct symtable *st, asdl_seq *args);
static int symtable_visit_argannotations(struct symtable *st, asdl_seq *args);
static int symtable_implicit_arg(struct symtable *st, int pos);
static int symtable_visit_annotations(struct symtable *st, stmt_ty s);
+static int symtable_visit_withitem(struct symtable *st, withitem_ty item);
static identifier top = NULL, lambda = NULL, genexpr = NULL,
@@ -223,17 +220,40 @@ symtable_new(void)
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 seems too
+ restrictive (it caused at least one test to fail) so a factor is
+ used to allow deeper recursion when compiling an expression.
+
+ Using a scaling factor means this should automatically adjust when
+ the recursion limit is adjusted for small or large C stack allocations.
+*/
+#define COMPILER_STACK_FRAME_SCALE 3
+
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 counters */
+ tstate = PyThreadState_GET();
+ if (!tstate) {
+ PySymtable_Free(st);
+ return NULL;
+ }
+ st->recursion_depth = tstate->recursion_depth * COMPILER_STACK_FRAME_SCALE;
+ st->recursion_limit = Py_GetRecursionLimit() * 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)) {
@@ -752,7 +772,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
goto error;
}
- /* Recursively call analyze_block() on each child block.
+ /* Recursively call analyze_child_block() on each child block.
newbound, newglobal now contain the names visible in
nested blocks. The free variables in the children will
@@ -895,18 +915,15 @@ symtable_warn(struct symtable *st, char *msg, int lineno)
static int
symtable_exit_block(struct symtable *st, void *ast)
{
- Py_ssize_t end;
-
- Py_CLEAR(st->st_cur);
- end = PyList_GET_SIZE(st->st_stack) - 1;
- if (end >= 0) {
- st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack,
- end);
- if (st->st_cur == NULL)
- return 0;
- Py_INCREF(st->st_cur);
- if (PySequence_DelItem(st->st_stack, end) < 0)
+ Py_ssize_t size;
+
+ st->st_cur = NULL;
+ size = PyList_GET_SIZE(st->st_stack);
+ if (size) {
+ if (PyList_SetSlice(st->st_stack, size - 1, size, NULL) < 0)
return 0;
+ if (--size)
+ st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack, size - 1);
}
return 1;
}
@@ -915,23 +932,23 @@ static int
symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
void *ast, int lineno, int col_offset)
{
- PySTEntryObject *prev = NULL;
+ PySTEntryObject *prev = NULL, *ste;
- if (st->st_cur) {
- prev = st->st_cur;
- if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) {
- return 0;
- }
- Py_DECREF(st->st_cur);
- }
- st->st_cur = ste_new(st, name, block, ast, lineno, col_offset);
- if (st->st_cur == NULL)
+ ste = ste_new(st, name, block, ast, lineno, col_offset);
+ if (ste == NULL)
+ return 0;
+ if (PyList_Append(st->st_stack, (PyObject *)ste) < 0) {
+ Py_DECREF(ste);
return 0;
+ }
+ prev = st->st_cur;
+ /* The entry is owned by the stack. Borrow it for st_cur. */
+ Py_DECREF(ste);
+ st->st_cur = ste;
if (block == ModuleBlock)
st->st_global = st->st_cur->ste_symbols;
if (prev) {
- if (PyList_Append(prev->ste_children,
- (PyObject *)st->st_cur) < 0) {
+ if (PyList_Append(prev->ste_children, (PyObject *)ste) < 0) {
return 0;
}
}
@@ -1019,17 +1036,17 @@ error:
VISIT_SEQ_TAIL permits the start of an ASDL sequence to be skipped, which is
useful if the first node in the sequence requires special treatment.
+
+ VISIT_QUIT macro returns the specified value exiting from the function but
+ first adjusts current recursion counter depth.
*/
+#define VISIT_QUIT(ST, X) \
+ return --(ST)->recursion_depth,(X)
+
#define VISIT(ST, TYPE, V) \
if (!symtable_visit_ ## TYPE((ST), (V))) \
- return 0;
-
-#define VISIT_IN_BLOCK(ST, TYPE, V, S) \
- if (!symtable_visit_ ## TYPE((ST), (V))) { \
- symtable_exit_block((ST), (S)); \
- return 0; \
- }
+ VISIT_QUIT((ST), 0);
#define VISIT_SEQ(ST, TYPE, SEQ) { \
int i; \
@@ -1037,19 +1054,7 @@ error:
for (i = 0; i < asdl_seq_LEN(seq); i++) { \
TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
if (!symtable_visit_ ## TYPE((ST), elt)) \
- return 0; \
- } \
-}
-
-#define VISIT_SEQ_IN_BLOCK(ST, TYPE, SEQ, S) { \
- int i; \
- asdl_seq *seq = (SEQ); /* avoid variable capture */ \
- for (i = 0; i < asdl_seq_LEN(seq); i++) { \
- TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
- if (!symtable_visit_ ## TYPE((ST), elt)) { \
- symtable_exit_block((ST), (S)); \
- return 0; \
- } \
+ VISIT_QUIT((ST), 0); \
} \
}
@@ -1059,19 +1064,7 @@ error:
for (i = (START); i < asdl_seq_LEN(seq); i++) { \
TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
if (!symtable_visit_ ## TYPE((ST), elt)) \
- return 0; \
- } \
-}
-
-#define VISIT_SEQ_TAIL_IN_BLOCK(ST, TYPE, SEQ, START, S) { \
- int i; \
- asdl_seq *seq = (SEQ); /* avoid variable capture */ \
- for (i = (START); i < asdl_seq_LEN(seq); i++) { \
- TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \
- if (!symtable_visit_ ## TYPE((ST), elt)) { \
- symtable_exit_block((ST), (S)); \
- return 0; \
- } \
+ VISIT_QUIT((ST), 0); \
} \
}
@@ -1082,7 +1075,7 @@ error:
expr_ty elt = (expr_ty)asdl_seq_GET(seq, i); \
if (!elt) continue; /* can be NULL */ \
if (!symtable_visit_expr((ST), elt)) \
- return 0; \
+ VISIT_QUIT((ST), 0); \
} \
}
@@ -1107,32 +1100,37 @@ symtable_new_tmpname(struct symtable *st)
static int
symtable_visit_stmt(struct symtable *st, stmt_ty s)
{
+ if (++st->recursion_depth > st->recursion_limit) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "maximum recursion depth exceeded during compilation");
+ VISIT_QUIT(st, 0);
+ }
switch (s->kind) {
case FunctionDef_kind:
if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL))
- return 0;
+ VISIT_QUIT(st, 0);
if (s->v.FunctionDef.args->defaults)
VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults);
if (s->v.FunctionDef.args->kw_defaults)
VISIT_KWONLYDEFAULTS(st,
s->v.FunctionDef.args->kw_defaults);
if (!symtable_visit_annotations(st, s))
- return 0;
+ VISIT_QUIT(st, 0);
if (s->v.FunctionDef.decorator_list)
VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list);
if (!symtable_enter_block(st, s->v.FunctionDef.name,
FunctionBlock, (void *)s, s->lineno,
s->col_offset))
- return 0;
- VISIT_IN_BLOCK(st, arguments, s->v.FunctionDef.args, s);
- VISIT_SEQ_IN_BLOCK(st, stmt, s->v.FunctionDef.body, s);
+ VISIT_QUIT(st, 0);
+ VISIT(st, arguments, s->v.FunctionDef.args);
+ VISIT_SEQ(st, stmt, s->v.FunctionDef.body);
if (!symtable_exit_block(st, s))
- return 0;
+ VISIT_QUIT(st, 0);
break;
case ClassDef_kind: {
PyObject *tmp;
if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL))
- return 0;
+ VISIT_QUIT(st, 0);
VISIT_SEQ(st, expr, s->v.ClassDef.bases);
VISIT_SEQ(st, keyword, s->v.ClassDef.keywords);
if (s->v.ClassDef.starargs)
@@ -1143,34 +1141,26 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list);
if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock,
(void *)s, s->lineno, s->col_offset))
- return 0;
+ VISIT_QUIT(st, 0);
if (!GET_IDENTIFIER(__class__) ||
!symtable_add_def(st, __class__, DEF_LOCAL) ||
!GET_IDENTIFIER(__locals__) ||
!symtable_add_def(st, __locals__, DEF_PARAM)) {
symtable_exit_block(st, s);
- return 0;
+ VISIT_QUIT(st, 0);
}
tmp = st->st_private;
st->st_private = s->v.ClassDef.name;
- VISIT_SEQ_IN_BLOCK(st, stmt, s->v.ClassDef.body, s);
+ VISIT_SEQ(st, stmt, s->v.ClassDef.body);
st->st_private = tmp;
if (!symtable_exit_block(st, s))
- return 0;
+ VISIT_QUIT(st, 0);
break;
}
case Return_kind:
if (s->v.Return.value) {
VISIT(st, expr, s->v.Return.value);
st->st_cur->ste_returns_value = 1;
- if (st->st_cur->ste_generator) {
- PyErr_SetString(PyExc_SyntaxError,
- RETURN_VAL_IN_GENERATOR);
- PyErr_SyntaxLocationEx(st->st_filename,
- s->lineno,
- s->col_offset);
- return 0;
- }
}
break;
case Delete_kind:
@@ -1207,19 +1197,16 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
case Raise_kind:
if (s->v.Raise.exc) {
VISIT(st, expr, s->v.Raise.exc);
- if (s->v.Raise.cause) {
- VISIT(st, expr, s->v.Raise.cause);
- }
+ if (s->v.Raise.cause) {
+ VISIT(st, expr, s->v.Raise.cause);
+ }
}
break;
- case TryExcept_kind:
- VISIT_SEQ(st, stmt, s->v.TryExcept.body);
- VISIT_SEQ(st, stmt, s->v.TryExcept.orelse);
- VISIT_SEQ(st, excepthandler, s->v.TryExcept.handlers);
- break;
- case TryFinally_kind:
- VISIT_SEQ(st, stmt, s->v.TryFinally.body);
- VISIT_SEQ(st, stmt, s->v.TryFinally.finalbody);
+ case Try_kind:
+ VISIT_SEQ(st, stmt, s->v.Try.body);
+ VISIT_SEQ(st, stmt, s->v.Try.orelse);
+ VISIT_SEQ(st, excepthandler, s->v.Try.handlers);
+ VISIT_SEQ(st, stmt, s->v.Try.finalbody);
break;
case Assert_kind:
VISIT(st, expr, s->v.Assert.test);
@@ -1249,12 +1236,14 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
asdl_seq *seq = s->v.Global.names;
for (i = 0; i < asdl_seq_LEN(seq); i++) {
identifier name = (identifier)asdl_seq_GET(seq, i);
- char *c_name = _PyUnicode_AsString(name);
long cur = symtable_lookup(st, name);
if (cur < 0)
- return 0;
+ VISIT_QUIT(st, 0);
if (cur & (DEF_LOCAL | USE)) {
char buf[256];
+ char *c_name = _PyUnicode_AsString(name);
+ if (!c_name)
+ return 0;
if (cur & DEF_LOCAL)
PyOS_snprintf(buf, sizeof(buf),
GLOBAL_AFTER_ASSIGN,
@@ -1264,10 +1253,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
GLOBAL_AFTER_USE,
c_name);
if (!symtable_warn(st, buf, s->lineno))
- return 0;
+ VISIT_QUIT(st, 0);
}
if (!symtable_add_def(st, name, DEF_GLOBAL))
- return 0;
+ VISIT_QUIT(st, 0);
}
break;
}
@@ -1276,12 +1265,14 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
asdl_seq *seq = s->v.Nonlocal.names;
for (i = 0; i < asdl_seq_LEN(seq); i++) {
identifier name = (identifier)asdl_seq_GET(seq, i);
- char *c_name = _PyUnicode_AsString(name);
long cur = symtable_lookup(st, name);
if (cur < 0)
- return 0;
+ VISIT_QUIT(st, 0);
if (cur & (DEF_LOCAL | USE)) {
char buf[256];
+ char *c_name = _PyUnicode_AsString(name);
+ if (!c_name)
+ return 0;
if (cur & DEF_LOCAL)
PyOS_snprintf(buf, sizeof(buf),
NONLOCAL_AFTER_ASSIGN,
@@ -1291,10 +1282,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
NONLOCAL_AFTER_USE,
c_name);
if (!symtable_warn(st, buf, s->lineno))
- return 0;
+ VISIT_QUIT(st, 0);
}
if (!symtable_add_def(st, name, DEF_NONLOCAL))
- return 0;
+ VISIT_QUIT(st, 0);
}
break;
}
@@ -1307,19 +1298,21 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
/* nothing to do here */
break;
case With_kind:
- VISIT(st, expr, s->v.With.context_expr);
- if (s->v.With.optional_vars) {
- VISIT(st, expr, s->v.With.optional_vars);
- }
+ VISIT_SEQ(st, withitem, s->v.With.items);
VISIT_SEQ(st, stmt, s->v.With.body);
break;
}
- return 1;
+ VISIT_QUIT(st, 1);
}
static int
symtable_visit_expr(struct symtable *st, expr_ty e)
{
+ if (++st->recursion_depth > st->recursion_limit) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "maximum recursion depth exceeded during compilation");
+ VISIT_QUIT(st, 0);
+ }
switch (e->kind) {
case BoolOp_kind:
VISIT_SEQ(st, expr, e->v.BoolOp.values);
@@ -1333,7 +1326,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
break;
case Lambda_kind: {
if (!GET_IDENTIFIER(lambda))
- return 0;
+ VISIT_QUIT(st, 0);
if (e->v.Lambda.args->defaults)
VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
if (e->v.Lambda.args->kw_defaults)
@@ -1342,11 +1335,11 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
if (!symtable_enter_block(st, lambda,
FunctionBlock, (void *)e, e->lineno,
e->col_offset))
- return 0;
- VISIT_IN_BLOCK(st, arguments, e->v.Lambda.args, (void*)e);
- VISIT_IN_BLOCK(st, expr, e->v.Lambda.body, (void*)e);
+ VISIT_QUIT(st, 0);
+ VISIT(st, arguments, e->v.Lambda.args);
+ VISIT(st, expr, e->v.Lambda.body);
if (!symtable_exit_block(st, (void *)e))
- return 0;
+ VISIT_QUIT(st, 0);
break;
}
case IfExp_kind:
@@ -1363,31 +1356,28 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
break;
case GeneratorExp_kind:
if (!symtable_visit_genexp(st, e))
- return 0;
+ VISIT_QUIT(st, 0);
break;
case ListComp_kind:
if (!symtable_visit_listcomp(st, e))
- return 0;
+ VISIT_QUIT(st, 0);
break;
case SetComp_kind:
if (!symtable_visit_setcomp(st, e))
- return 0;
+ VISIT_QUIT(st, 0);
break;
case DictComp_kind:
if (!symtable_visit_dictcomp(st, e))
- return 0;
+ VISIT_QUIT(st, 0);
break;
case Yield_kind:
if (e->v.Yield.value)
VISIT(st, expr, e->v.Yield.value);
st->st_cur->ste_generator = 1;
- if (st->st_cur->ste_returns_value) {
- PyErr_SetString(PyExc_SyntaxError,
- RETURN_VAL_IN_GENERATOR);
- PyErr_SyntaxLocationEx(st->st_filename,
- e->lineno, e->col_offset);
- return 0;
- }
+ break;
+ case YieldFrom_kind:
+ VISIT(st, expr, e->v.YieldFrom.value);
+ st->st_cur->ste_generator = 1;
break;
case Compare_kind:
VISIT(st, expr, e->v.Compare.left);
@@ -1422,14 +1412,14 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
case Name_kind:
if (!symtable_add_def(st, e->v.Name.id,
e->v.Name.ctx == Load ? USE : DEF_LOCAL))
- return 0;
+ VISIT_QUIT(st, 0);
/* Special-case super: it counts as a use of __class__ */
if (e->v.Name.ctx == Load &&
st->st_cur->ste_type == FunctionBlock &&
!PyUnicode_CompareWithASCIIString(e->v.Name.id, "super")) {
if (!GET_IDENTIFIER(__class__) ||
!symtable_add_def(st, __class__, USE))
- return 0;
+ VISIT_QUIT(st, 0);
}
break;
/* child nodes of List and Tuple will have expr_context set */
@@ -1440,7 +1430,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT_SEQ(st, expr, e->v.Tuple.elts);
break;
}
- return 1;
+ VISIT_QUIT(st, 1);
}
static int
@@ -1545,6 +1535,16 @@ symtable_visit_excepthandler(struct symtable *st, excepthandler_ty eh)
return 1;
}
+static int
+symtable_visit_withitem(struct symtable *st, withitem_ty item)
+{
+ VISIT(st, expr, item->context_expr);
+ if (item->optional_vars) {
+ VISIT(st, expr, item->optional_vars);
+ }
+ return 1;
+}
+
static int
symtable_visit_alias(struct symtable *st, alias_ty a)
@@ -1555,10 +1555,10 @@ symtable_visit_alias(struct symtable *st, alias_ty a)
*/
PyObject *store_name;
PyObject *name = (a->asname == NULL) ? a->name : a->asname;
- const Py_UNICODE *base = PyUnicode_AS_UNICODE(name);
- Py_UNICODE *dot = Py_UNICODE_strchr(base, '.');
- if (dot) {
- store_name = PyUnicode_FromUnicode(base, dot - base);
+ Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0,
+ PyUnicode_GET_LENGTH(name), 1);
+ if (dot != -1) {
+ store_name = PyUnicode_Substring(name, 0, dot);
if (!store_name)
return 0;
}
@@ -1655,13 +1655,12 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e,
symtable_exit_block(st, (void *)e);
return 0;
}
- VISIT_IN_BLOCK(st, expr, outermost->target, (void*)e);
- VISIT_SEQ_IN_BLOCK(st, expr, outermost->ifs, (void*)e);
- VISIT_SEQ_TAIL_IN_BLOCK(st, comprehension,
- generators, 1, (void*)e);
+ VISIT(st, expr, outermost->target);
+ VISIT_SEQ(st, expr, outermost->ifs);
+ VISIT_SEQ_TAIL(st, comprehension, generators, 1);
if (value)
- VISIT_IN_BLOCK(st, expr, value, (void*)e);
- VISIT_IN_BLOCK(st, expr, elt, (void*)e);
+ VISIT(st, expr, value);
+ VISIT(st, expr, elt);
return symtable_exit_block(st, (void *)e);
}