mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
35c38eaeae
commit
1955fcf67a
|
@ -686,7 +686,8 @@ static node *get_rawdocstring(node *);
|
||||||
static int get_ref_type(struct compiling *, char *);
|
static int get_ref_type(struct compiling *, char *);
|
||||||
|
|
||||||
/* symtable operations */
|
/* symtable operations */
|
||||||
static int symtable_build(struct compiling *, node *);
|
static struct symtable *symtable_build(node *, PyFutureFeatures *,
|
||||||
|
const char *filename);
|
||||||
static int symtable_load_symbols(struct compiling *);
|
static int symtable_load_symbols(struct compiling *);
|
||||||
static struct symtable *symtable_init(void);
|
static struct symtable *symtable_init(void);
|
||||||
static void symtable_enter_scope(struct symtable *, char *, int, int);
|
static void symtable_enter_scope(struct symtable *, char *, int, int);
|
||||||
|
@ -4250,26 +4251,12 @@ PyNode_CompileSymtable(node *n, const char *filename)
|
||||||
ff = PyNode_Future(n, filename);
|
ff = PyNode_Future(n, filename);
|
||||||
if (ff == NULL)
|
if (ff == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
st = symtable_build(n, ff, filename);
|
||||||
st = symtable_init();
|
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
PyObject_FREE((void *)ff);
|
PyObject_FREE((void *)ff);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
st->st_future = ff;
|
|
||||||
symtable_enter_scope(st, TOP, TYPE(n), n->n_lineno);
|
|
||||||
if (st->st_errors > 0)
|
|
||||||
goto fail;
|
|
||||||
symtable_node(st, n);
|
|
||||||
if (st->st_errors > 0)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
return st;
|
return st;
|
||||||
fail:
|
|
||||||
PyObject_FREE((void *)ff);
|
|
||||||
st->st_future = NULL;
|
|
||||||
PySymtable_Free(st);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyCodeObject *
|
static PyCodeObject *
|
||||||
|
@ -4319,10 +4306,14 @@ jcompile(node *n, const char *filename, struct compiling *base,
|
||||||
sc.c_future->ff_features = merged;
|
sc.c_future->ff_features = merged;
|
||||||
flags->cf_flags = merged;
|
flags->cf_flags = merged;
|
||||||
}
|
}
|
||||||
if (symtable_build(&sc, n) < 0) {
|
sc.c_symtable = symtable_build(n, sc.c_future, sc.c_filename);
|
||||||
|
if (sc.c_symtable == NULL) {
|
||||||
com_free(&sc);
|
com_free(&sc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/* reset symbol table for second pass */
|
||||||
|
sc.c_symtable->st_nscopes = 1;
|
||||||
|
sc.c_symtable->st_pass = 2;
|
||||||
}
|
}
|
||||||
co = NULL;
|
co = NULL;
|
||||||
if (symtable_load_symbols(&sc) < 0) {
|
if (symtable_load_symbols(&sc) < 0) {
|
||||||
|
@ -4443,6 +4434,15 @@ get_ref_type(struct compiling *c, char *name)
|
||||||
static int
|
static int
|
||||||
issue_warning(const char *msg, const char *filename, int lineno)
|
issue_warning(const char *msg, const char *filename, int lineno)
|
||||||
{
|
{
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
/* This can happen because symtable_node continues
|
||||||
|
processing even after raising a SyntaxError.
|
||||||
|
Calling PyErr_WarnExplicit now would clobber the
|
||||||
|
pending exception; instead we fail and let that
|
||||||
|
exception propagate.
|
||||||
|
*/
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, filename,
|
if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, filename,
|
||||||
lineno, NULL, NULL) < 0) {
|
lineno, NULL, NULL) < 0) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
|
if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) {
|
||||||
|
@ -4466,23 +4466,37 @@ symtable_warn(struct symtable *st, char *msg)
|
||||||
|
|
||||||
/* Helper function for setting lineno and filename */
|
/* Helper function for setting lineno and filename */
|
||||||
|
|
||||||
static int
|
static struct symtable *
|
||||||
symtable_build(struct compiling *c, node *n)
|
symtable_build(node *n, PyFutureFeatures *ff, const char *filename)
|
||||||
{
|
{
|
||||||
if ((c->c_symtable = symtable_init()) == NULL)
|
struct symtable *st;
|
||||||
return -1;
|
|
||||||
c->c_symtable->st_future = c->c_future;
|
st = symtable_init();
|
||||||
c->c_symtable->st_filename = c->c_filename;
|
if (st == NULL)
|
||||||
symtable_enter_scope(c->c_symtable, TOP, TYPE(n), n->n_lineno);
|
return NULL;
|
||||||
if (c->c_symtable->st_errors > 0)
|
st->st_future = ff;
|
||||||
return -1;
|
st->st_filename = filename;
|
||||||
symtable_node(c->c_symtable, n);
|
symtable_enter_scope(st, TOP, TYPE(n), n->n_lineno);
|
||||||
if (c->c_symtable->st_errors > 0)
|
if (st->st_errors > 0)
|
||||||
return -1;
|
goto fail;
|
||||||
/* reset for second pass */
|
symtable_node(st, n);
|
||||||
c->c_symtable->st_nscopes = 1;
|
if (st->st_errors > 0)
|
||||||
c->c_symtable->st_pass = 2;
|
goto fail;
|
||||||
return 0;
|
return st;
|
||||||
|
fail:
|
||||||
|
if (!PyErr_Occurred()) {
|
||||||
|
/* This could happen because after a syntax error is
|
||||||
|
detected, the symbol-table-building continues for
|
||||||
|
a while, and PyErr_Clear() might erroneously be
|
||||||
|
called during that process. One such case has been
|
||||||
|
fixed, but there might be more (now or later).
|
||||||
|
*/
|
||||||
|
PyErr_SetString(PyExc_SystemError, "lost exception");
|
||||||
|
}
|
||||||
|
st->st_future = NULL;
|
||||||
|
st->st_filename = NULL;
|
||||||
|
PySymtable_Free(st);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
Loading…
Reference in New Issue