diff options
author | Phillip J. Eby <pje@telecommunity.com> | 2006-04-15 01:02:17 (GMT) |
---|---|---|
committer | Phillip J. Eby <pje@telecommunity.com> | 2006-04-15 01:02:17 (GMT) |
commit | 8ebb28df3a6e0bce240b6c2aa20d7aa5a4dfef39 (patch) | |
tree | 066424b3c1e37a639145e6453cb4f7d1b83b41e1 /Objects | |
parent | 3cfea2dc987b90e637c4cbd5db5dc1f542e448b2 (diff) | |
download | cpython-8ebb28df3a6e0bce240b6c2aa20d7aa5a4dfef39.zip cpython-8ebb28df3a6e0bce240b6c2aa20d7aa5a4dfef39.tar.gz cpython-8ebb28df3a6e0bce240b6c2aa20d7aa5a4dfef39.tar.bz2 |
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.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/frameobject.c | 20 | ||||
-rw-r--r-- | Objects/genobject.c | 21 |
2 files changed, 22 insertions, 19 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 8aa3377..49f74cb 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -454,9 +454,15 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg) 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 @@ frame_clear(PyFrameObject *f) 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); } } } diff --git a/Objects/genobject.c b/Objects/genobject.c index ccce315..c73a53cb 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -35,7 +35,7 @@ gen_dealloc(PyGenObject *gen) } _PyObject_GC_UNTRACK(self); - Py_XDECREF(gen->gi_frame); + Py_CLEAR(gen->gi_frame); PyObject_GC_Del(gen); } @@ -130,8 +130,8 @@ gen_close(PyGenObject *gen, PyObject *args) "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 @@ PyDoc_STRVAR(throw_doc, 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 @@ PyTypeObject PyGen_Type = { 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ - + 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ @@ -366,15 +366,16 @@ PyGen_NeedsFinalizing(PyGenObject *gen) 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; } |