mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	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
					
				
					 1 changed files with 47 additions and 33 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Hylton
						Jeremy Hylton