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

Skip to content

Commit 1955fcf

Browse files
committed
SF patch 763201: handling of SyntaxErrors in symbol table build
Fixes for three related bugs, including errors that caused a script to be ignored without printing an error message. The key problem was a bad interaction between syntax warnings and syntax errors. If an exception was already set when a warning was issued, the warning could clobber the exception. The PyErr_Occurred() check in issue_warning() isn't entirely satisfying (the caller should know whether there was already an error), but a better solution isn't immediately obvious. Bug fix candidate.
1 parent 35c38ea commit 1955fcf

1 file changed

Lines changed: 47 additions & 33 deletions

File tree

Python/compile.c

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,8 @@ static node *get_rawdocstring(node *);
686686
static int get_ref_type(struct compiling *, char *);
687687

688688
/* symtable operations */
689-
static int symtable_build(struct compiling *, node *);
689+
static struct symtable *symtable_build(node *, PyFutureFeatures *,
690+
const char *filename);
690691
static int symtable_load_symbols(struct compiling *);
691692
static struct symtable *symtable_init(void);
692693
static void symtable_enter_scope(struct symtable *, char *, int, int);
@@ -4250,26 +4251,12 @@ PyNode_CompileSymtable(node *n, const char *filename)
42504251
ff = PyNode_Future(n, filename);
42514252
if (ff == NULL)
42524253
return NULL;
4253-
4254-
st = symtable_init();
4254+
st = symtable_build(n, ff, filename);
42554255
if (st == NULL) {
42564256
PyObject_FREE((void *)ff);
42574257
return NULL;
42584258
}
4259-
st->st_future = ff;
4260-
symtable_enter_scope(st, TOP, TYPE(n), n->n_lineno);
4261-
if (st->st_errors > 0)
4262-
goto fail;
4263-
symtable_node(st, n);
4264-
if (st->st_errors > 0)
4265-
goto fail;
4266-
42674259
return st;
4268-
fail:
4269-
PyObject_FREE((void *)ff);
4270-
st->st_future = NULL;
4271-
PySymtable_Free(st);
4272-
return NULL;
42734260
}
42744261

42754262
static PyCodeObject *
@@ -4319,10 +4306,14 @@ jcompile(node *n, const char *filename, struct compiling *base,
43194306
sc.c_future->ff_features = merged;
43204307
flags->cf_flags = merged;
43214308
}
4322-
if (symtable_build(&sc, n) < 0) {
4309+
sc.c_symtable = symtable_build(n, sc.c_future, sc.c_filename);
4310+
if (sc.c_symtable == NULL) {
43234311
com_free(&sc);
43244312
return NULL;
43254313
}
4314+
/* reset symbol table for second pass */
4315+
sc.c_symtable->st_nscopes = 1;
4316+
sc.c_symtable->st_pass = 2;
43264317
}
43274318
co = NULL;
43284319
if (symtable_load_symbols(&sc) < 0) {
@@ -4443,6 +4434,15 @@ get_ref_type(struct compiling *c, char *name)
44434434
static int
44444435
issue_warning(const char *msg, const char *filename, int lineno)
44454436
{
4437+
if (PyErr_Occurred()) {
4438+
/* This can happen because symtable_node continues
4439+
processing even after raising a SyntaxError.
4440+
Calling PyErr_WarnExplicit now would clobber the
4441+
pending exception; instead we fail and let that
4442+
exception propagate.
4443+
*/
4444+
return -1;
4445+
}
44464446
if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, filename,
44474447
lineno, NULL, NULL) < 0) {
44484448
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
@@ -4466,23 +4466,37 @@ symtable_warn(struct symtable *st, char *msg)
44664466

44674467
/* Helper function for setting lineno and filename */
44684468

4469-
static int
4470-
symtable_build(struct compiling *c, node *n)
4469+
static struct symtable *
4470+
symtable_build(node *n, PyFutureFeatures *ff, const char *filename)
44714471
{
4472-
if ((c->c_symtable = symtable_init()) == NULL)
4473-
return -1;
4474-
c->c_symtable->st_future = c->c_future;
4475-
c->c_symtable->st_filename = c->c_filename;
4476-
symtable_enter_scope(c->c_symtable, TOP, TYPE(n), n->n_lineno);
4477-
if (c->c_symtable->st_errors > 0)
4478-
return -1;
4479-
symtable_node(c->c_symtable, n);
4480-
if (c->c_symtable->st_errors > 0)
4481-
return -1;
4482-
/* reset for second pass */
4483-
c->c_symtable->st_nscopes = 1;
4484-
c->c_symtable->st_pass = 2;
4485-
return 0;
4472+
struct symtable *st;
4473+
4474+
st = symtable_init();
4475+
if (st == NULL)
4476+
return NULL;
4477+
st->st_future = ff;
4478+
st->st_filename = filename;
4479+
symtable_enter_scope(st, TOP, TYPE(n), n->n_lineno);
4480+
if (st->st_errors > 0)
4481+
goto fail;
4482+
symtable_node(st, n);
4483+
if (st->st_errors > 0)
4484+
goto fail;
4485+
return st;
4486+
fail:
4487+
if (!PyErr_Occurred()) {
4488+
/* This could happen because after a syntax error is
4489+
detected, the symbol-table-building continues for
4490+
a while, and PyErr_Clear() might erroneously be
4491+
called during that process. One such case has been
4492+
fixed, but there might be more (now or later).
4493+
*/
4494+
PyErr_SetString(PyExc_SystemError, "lost exception");
4495+
}
4496+
st->st_future = NULL;
4497+
st->st_filename = NULL;
4498+
PySymtable_Free(st);
4499+
return NULL;
44864500
}
44874501

44884502
static int

0 commit comments

Comments
 (0)