Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2b13ce8

Browse files
committed
Try to avoid creating reference cycles involving generators. Only keep a
reference to f_back when its really needed. Do a little whitespace normalization as well. This whole file is a big war between tabs and spaces but now is probably not the time to reindent everything.
1 parent 2942131 commit 2b13ce8

1 file changed

Lines changed: 27 additions & 14 deletions

File tree

Python/ceval.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ gen_dealloc(genobject *gen)
138138
static PyObject *
139139
gen_iternext(genobject *gen)
140140
{
141+
PyThreadState *tstate = PyThreadState_GET();
141142
PyFrameObject *f = gen->frame;
142143
PyObject *result;
143144

@@ -149,15 +150,24 @@ gen_iternext(genobject *gen)
149150
if (f->f_stackbottom == NULL) {
150151
return NULL;
151152
}
152-
gen->running = 1;
153+
154+
/* Generators always return to their most recent caller, not
155+
* necessarily their creator. */
156+
Py_INCREF(tstate->frame);
157+
assert(f->f_back == NULL);
158+
f->f_back = tstate->frame;
159+
160+
gen->running = 1;
153161
result = eval_frame(f);
154-
gen->running = 0;
155-
/* The connection between this frame and its parent is over now, so
156-
must NULL out f_back lest it get decref'ed when gen dies (note
157-
that eval_frame sets f->f_back without bumping its refcount: we
158-
never had a fully legit reference to it). */
162+
gen->running = 0;
163+
164+
/* Don't keep the reference to f_back any longer than necessary. It
165+
* may keep a chain of frames alive or it could create a reference
166+
* cycle. */
167+
Py_DECREF(f->f_back);
159168
f->f_back = NULL;
160-
return result;
169+
170+
return result;
161171
}
162172

163173
static PyObject *
@@ -168,12 +178,12 @@ gen_next(genobject *gen, PyObject *args)
168178
if (!PyArg_ParseTuple(args, ":next"))
169179
return NULL;
170180

171-
result = gen_iternext(gen);
181+
result = gen_iternext(gen);
172182

173-
if (result == NULL && !PyErr_Occurred()) {
183+
if (result == NULL && !PyErr_Occurred()) {
174184
PyErr_SetObject(PyExc_StopIteration, Py_None);
175185
return NULL;
176-
}
186+
}
177187

178188
return result;
179189
}
@@ -568,9 +578,7 @@ eval_frame(PyFrameObject *f)
568578
return NULL;
569579
}
570580

571-
f->f_back = tstate->frame;
572581
tstate->frame = f;
573-
574582
co = f->f_code;
575583
fastlocals = f->f_localsplus;
576584
freevars = f->f_localsplus + f->f_nlocals;
@@ -2482,8 +2490,13 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
24822490
}
24832491

24842492
if (co->co_flags & CO_GENERATOR) {
2485-
/* create a new generator that owns the ready to run frame
2486-
* and return that as the value */
2493+
/* Don't need to keep the reference to f_back, it will be set
2494+
* when the generator is resumed. */
2495+
Py_DECREF(f->f_back);
2496+
f->f_back = NULL;
2497+
2498+
/* Create a new generator that owns the ready to run frame
2499+
* and return that as the value. */
24872500
return gen_new(f);
24882501
}
24892502

0 commit comments

Comments
 (0)