[Python-checkins] r45409 - in python/trunk: Lib/test/test_generators.py Objects/frameobject.c Objects/genobject.c
phillip.eby
python-checkins at python.org
Sat Apr 15 03:02:21 CEST 2006
Author: phillip.eby
Date: Sat Apr 15 03:02:17 2006
New Revision: 45409
Modified:
python/trunk/Lib/test/test_generators.py
python/trunk/Objects/frameobject.c
python/trunk/Objects/genobject.c
Log:
Fix SF#1470508: crash in generator cycle finalization. There were two
problems: first, PyGen_NeedsFinalizing() had an off-by-one bug that
prevented it from ever saying a generator didn't need finalizing, and
second, frame objects cleared themselves in a way that caused their
owning generator to think they were still executable, causing a double
deallocation of objects on the value stack if there was still a loop
on the block stack. This revision also removes some unnecessary
close() operations from test_generators that are now appropriately
handled by the cycle collector.
Modified: python/trunk/Lib/test/test_generators.py
==============================================================================
--- python/trunk/Lib/test/test_generators.py (original)
+++ python/trunk/Lib/test/test_generators.py Sat Apr 15 03:02:17 2006
@@ -421,7 +421,6 @@
... self.name = name
... self.parent = None
... self.generator = self.generate()
-... self.close = self.generator.close
...
... def generate(self):
... while not self.parent:
@@ -484,8 +483,6 @@
merged A into G
A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G
->>> for s in sets: s.close() # break cycles
-
"""
# Emacs turd '
@@ -593,7 +590,6 @@
... def __init__(self, g):
... self.sofar = []
... self.fetch = g.next
-... self.close = g.close
...
... def __getitem__(self, i):
... sofar, fetch = self.sofar, self.fetch
@@ -624,8 +620,6 @@
[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
->>> m235.close()
-
Ye olde Fibonacci generator, LazyList style.
>>> def fibgen(a, b):
@@ -648,7 +642,6 @@
>>> fib = LazyList(fibgen(1, 2))
>>> firstn(iter(fib), 17)
[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]
->>> fib.close()
Running after your tail with itertools.tee (new in version 2.4)
Modified: python/trunk/Objects/frameobject.c
==============================================================================
--- python/trunk/Objects/frameobject.c (original)
+++ python/trunk/Objects/frameobject.c Sat Apr 15 03:02:17 2006
@@ -454,9 +454,15 @@
static void
frame_clear(PyFrameObject *f)
{
- PyObject **fastlocals, **p;
+ PyObject **fastlocals, **p, **oldtop;
int i, slots;
+ oldtop = f->f_stacktop;
+
+ /* Before anything else, make sure that this frame is clearly marked
+ as being defunct! */
+ f->f_stacktop = NULL;
+
Py_XDECREF(f->f_exc_type);
f->f_exc_type = NULL;
@@ -473,17 +479,13 @@
slots = f->f_nlocals + f->f_ncells + f->f_nfreevars;
fastlocals = f->f_localsplus;
for (i = slots; --i >= 0; ++fastlocals) {
- if (*fastlocals != NULL) {
- Py_XDECREF(*fastlocals);
- *fastlocals = NULL;
- }
+ Py_CLEAR(*fastlocals);
}
/* stack */
- if (f->f_stacktop != NULL) {
- for (p = f->f_valuestack; p < f->f_stacktop; p++) {
- Py_XDECREF(*p);
- *p = NULL;
+ if (oldtop != NULL) {
+ for (p = f->f_valuestack; p < oldtop; p++) {
+ Py_CLEAR(*p);
}
}
}
Modified: python/trunk/Objects/genobject.c
==============================================================================
--- python/trunk/Objects/genobject.c (original)
+++ python/trunk/Objects/genobject.c Sat Apr 15 03:02:17 2006
@@ -35,7 +35,7 @@
}
_PyObject_GC_UNTRACK(self);
- Py_XDECREF(gen->gi_frame);
+ Py_CLEAR(gen->gi_frame);
PyObject_GC_Del(gen);
}
@@ -130,8 +130,8 @@
"generator ignored GeneratorExit");
return NULL;
}
- if ( PyErr_ExceptionMatches(PyExc_StopIteration)
- || PyErr_ExceptionMatches(PyExc_GeneratorExit) )
+ if ( PyErr_ExceptionMatches(PyExc_StopIteration)
+ || PyErr_ExceptionMatches(PyExc_GeneratorExit) )
{
PyErr_Clear(); /* ignore these errors */
Py_INCREF(Py_None);
@@ -208,7 +208,7 @@
return next yielded value or raise StopIteration.");
static PyObject *
-gen_throw(PyGenObject *gen, PyObject *args)
+gen_throw(PyGenObject *gen, PyObject *args)
{
PyObject *typ;
PyObject *tb = NULL;
@@ -328,7 +328,7 @@
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
-
+
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
@@ -366,15 +366,16 @@
int i;
PyFrameObject *f = gen->gi_frame;
- if (f == NULL || f->f_stacktop==NULL || f->f_iblock<=0)
- return 0; /* no frame or no blockstack == no finalization */
+ if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0)
+ return 0; /* no frame or empty blockstack == no finalization */
- for (i=f->f_iblock; i>=0; i--) {
+ /* Any block type besides a loop requires cleanup. */
+ i = f->f_iblock;
+ while (--i >= 0) {
if (f->f_blockstack[i].b_type != SETUP_LOOP)
- /* any block type besides a loop requires cleanup */
return 1;
}
- /* No blocks except loops, it's safe to skip finalization */
+ /* No blocks except loops, it's safe to skip finalization. */
return 0;
}
More information about the Python-checkins
mailing list