summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2001-04-27 02:29:40 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2001-04-27 02:29:40 (GMT)
commitddc4fd03b1eadeab65f8e0dbf5b6f386ed419fbc (patch)
tree288c1648ee28f097444e9926b037e0295df0c71b
parent960d948e7ce536eb30b69add0c6fc2dc31c90a8e (diff)
downloadcpython-ddc4fd03b1eadeab65f8e0dbf5b6f386ed419fbc.zip
cpython-ddc4fd03b1eadeab65f8e0dbf5b6f386ed419fbc.tar.gz
cpython-ddc4fd03b1eadeab65f8e0dbf5b6f386ed419fbc.tar.bz2
Fix 2.1 nested scopes crash reported by Evan Simpson
The new test case demonstrates the bug. Be more careful in symtable_resolve_free() to add a var to cells or frees only if it won't be added under some other rule. XXX Add new assertion that will catch this bug.
-rw-r--r--Lib/test/output/test_scope1
-rw-r--r--Lib/test/test_scope.py11
-rw-r--r--Python/compile.c26
3 files changed, 32 insertions, 6 deletions
diff --git a/Lib/test/output/test_scope b/Lib/test/output/test_scope
index af7fe31..fcd4e7a 100644
--- a/Lib/test/output/test_scope
+++ b/Lib/test/output/test_scope
@@ -17,3 +17,4 @@ test_scope
16. check leaks
17. class and global
18. verify that locals() works
+19. var is bound and free in class
diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py
index 358c45a..c42d881 100644
--- a/Lib/test/test_scope.py
+++ b/Lib/test/test_scope.py
@@ -436,3 +436,14 @@ verify(d.has_key('h'))
del d['h']
verify(d == {'x': 2, 'y': 7, 'w': 6})
+print "19. var is bound and free in class"
+
+def f(x):
+ class C:
+ def m(self):
+ return x
+ a = x
+ return C
+
+inst = f(3)()
+verify(inst.a == inst.m())
diff --git a/Python/compile.c b/Python/compile.c
index cb85ce3..1f1d44c 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -4057,7 +4057,7 @@ symtable_init_info(struct symbol_info *si)
}
static int
-symtable_resolve_free(struct compiling *c, PyObject *name,
+symtable_resolve_free(struct compiling *c, PyObject *name, int flags,
struct symbol_info *si)
{
PyObject *dict, *v;
@@ -4067,11 +4067,19 @@ symtable_resolve_free(struct compiling *c, PyObject *name,
cell var). If it occurs in a class, then the class has a
method and a free variable with the same name.
*/
-
if (c->c_symtable->st_cur->ste_type == TYPE_FUNCTION) {
+ /* If it isn't declared locally, it can't be a cell. */
+ if (!(flags & (DEF_LOCAL | DEF_PARAM)))
+ return 0;
v = PyInt_FromLong(si->si_ncells++);
dict = c->c_cellvars;
} else {
+ /* If it is free anyway, then there is no need to do
+ anything here.
+ */
+ if (is_free(flags ^ DEF_FREE_CLASS)
+ || flags == DEF_FREE_CLASS)
+ return 0;
v = PyInt_FromLong(si->si_nfrees++);
dict = c->c_freevars;
}
@@ -4357,10 +4365,7 @@ symtable_load_symbols(struct compiling *c)
variables or declared global.
*/
if (flags & (DEF_FREE | DEF_FREE_CLASS)) {
- if ((ste->ste_type == TYPE_CLASS
- && flags != DEF_FREE_CLASS)
- || (flags & (DEF_LOCAL | DEF_PARAM)))
- symtable_resolve_free(c, name, &si);
+ symtable_resolve_free(c, name, flags, &si);
}
if (flags & DEF_STAR) {
@@ -4420,6 +4425,15 @@ symtable_load_symbols(struct compiling *c)
}
}
+ /*
+ fprintf(stderr,
+ "cells %d: %s\n"
+ "frees %d: %s\n",
+ si.si_ncells, PyObject_REPR(c->c_cellvars),
+ si.si_nfrees, PyObject_REPR(c->c_freevars));
+ */
+ assert(PyDict_Size(c->c_freevars) == si.si_nfrees);
+
if (si.si_ncells > 1) { /* one cell is always in order */
if (symtable_cellvar_offsets(&c->c_cellvars, c->c_argcount,
c->c_varnames, c->c_flags) < 0)