[Patches] [ python-Patches-763201 ] 3 bugs fixed: handling of SyntaxErrors in symbol table build

SourceForge.net noreply@sourceforge.net
Mon, 30 Jun 2003 06:48:26 -0700


Patches item #763201, was opened at 2003-06-30 07:48
Message generated for change (Tracker Item Submitted) made by Item Submitter
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=763201&group_id=5470

Category: Parser/Compiler
Group: Python 2.3
Status: Open
Resolution: None
Priority: 5
Submitted By: Steven Taschuk (staschuk)
Assigned to: Nobody/Anonymous (nobody)
Summary: 3 bugs fixed: handling of SyntaxErrors in symbol table build

Initial Comment:
All three bugs found in both 2.2.3 and 2.3b2.  It's one 
patch
instead of three because the fixes share a refactoring of
Python/compile.c:symtable_build.

Bug 1:  Wrong file name

    import symtable
    symtable.symtable('def foo(a): global a', 'spam', 'exec')

The error message says '<string>' instead of 'spam'.
(Cause: PyNode_CompileSymtable doesn't set 
st_filename.)

Bug 2:  Memory leak

    while True:
        try:
            compile('def foo(a): global a', 'spam', 'exec')
        except SyntaxError:
            pass

(Cause: symtable_build doesn't free c->c_symtable on 
error.)

The patch is missing a test case for this one; I don't see 
how to write it.

Bug 3:  Exception clobbered

    def foo(a):
        global a  # SyntaxError

    def bar():
        b = 1
        global b  # SyntaxWarning

Running this as a script, the SyntaxWarning is issued, 
and then
the interpreter dies silently (that is, without printing a
traceback reporting the SyntaxError).  Compiling it with 
compile()
causes a SystemError.  (Cause: see below.)

What to do about bugs 1 and 2 is obvious, but bug 3 
(which was
actually reported on c.l.py) is not so clear to me.  Here's 
how
the problem occurs:

symtable_global() sees the global statement in foo(), 
raises a
SyntaxError, increments st_errors, and returns.  
Processing
continues.  Later, symtable_global() sees the global 
statement in
bar() and issues a warning by (indirectly) calling
PyErr_WarnExplicit().  This call clears the SyntaxError, 
which is
still pending at that time.  (It's actually cleared during the
attempt to import the warnings module, in 
PyImport_Import, which
seems to think the exception was raised in 
PyEval_GetGlobals.)
But st_errors is still > 0, as it should be, so 
symtable_build()
returns -1 (resp.  PyNode_CompileSymtable, NULL), its 
callers
return their error values, etc., until eventually PyErr_Print
tries to print the exception that isn't there.

What the patch implements is this:

Do not issue SyntaxWarnings if an exception is pending; 
fail
instead and let that exception propagate.  Also, as a 
defensive
measure against other bugs of this type (present and 
future), when
returning with error from symtable_build(), verify that 
there's an
exception pending (and raise SystemError if not).  Finally,
refactor symtable_build() so PyNode_CompileSymtable 
can use it and
thereby benefit from that defensive measure.

Alternatives (and why I don't like them):

1. Do not try to continue processing after a SyntaxError is
raised.  (Seems like the Right Thing to me, but also 
seems to be
contrary to the intent of the existing code.  There are 
oodles of
places in compile.c which call symtable_node without 
checking
st_errors immediately afterwards.)

2. Put the check for a pending exception in 
PyErr_WarnExplicit()
instead of in the helper function in compile.c.  (Doesn't 
seem
like a common enough coding error to merit a check 
there.  In
symtable_node etc we deliberately let SyntaxErrors, er, 
"pend"
while we do a bit more compiling, so *there* it's worth 
checking.
Note that jcompile() already has a check for something 
similar,
though not for the symbol-table-building phase.)

3. Squirrel the pending exception away, issue the 
warning, then
restore the exception.  (Not worth the bother, IMO.  And 
if the
warning gets strengthened into an exception, should that 
exception
or the squirrelled one propagate?  Ick.)


----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=763201&group_id=5470