[Python-Dev] RE: [Python-checkins] python/dist/src/Modules
gcmodule.c,2.33.6.5,2.33.6.6
Tim Peters
tim.one@comcast.net
Thu, 03 Apr 2003 23:37:47 -0500
[jhylton@users.sourceforge.net]
> Modified Files:
> Tag: release22-maint
> gcmodule.c
> Log Message:
> Fix memory corruption in garbage collection.
> ...
> The problem with the previous revision is that it followed
> gc->gc.gc_next before calling has_finalizer(). If has_finalizer()
> gc->happened to deallocate the object FROM_GC(gc->gc.gc_next), then
> the next time through the loop gc would point to freed memory. The
> fix is to always follow the next pointer after calling
> has_finalizer().
Oops! I didn't see this before posting my "Boom" msg.
> Note that Python 2.3 does not have this problem, because
> has_finalizer() checks the tp_del slot and never runs Python code.
That part isn't so, alas: the program I posted in the "Boom" msg crashes
2.3, via the same mechanism:
return PyInstance_Check(op) ? PyObject_HasAttr(op, delstr) :
PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE) ?
op->ob_type->tp_del != NULL : 0;
It's the PyInstance_Check(op) path there that's still vulnerable. I'll poke
at that.
> Tim, Barry, and I peed away the better part of two days tracking this
> down.
> ! next = gc->gc.gc_next;
> if (has_finalizer(op)) {
> gc_list_remove(gc);
> gc_list_append(gc, finalizers);
> gc->gc.gc_refs = GC_MOVED;
> }
> }
> }
> --- 277,290 ----
> for (; gc != unreachable; gc=next) {
> PyObject *op = FROM_GC(gc);
> ! /* has_finalizer() may result in arbitrary Python
> ! code being run. */
> if (has_finalizer(op)) {
> + next = gc->gc.gc_next;
> gc_list_remove(gc);
> gc_list_append(gc, finalizers);
> gc->gc.gc_refs = GC_MOVED;
> }
> + else
> + next = gc->gc.gc_next;
> }
> }
Are we certain that has_finalizer() can't unlink gc itself from the
unreachable list? If it can, then
> + else
> + next = gc->gc.gc_next;
will set next to the content of free()ed memory. In fact, I believe the
Boom program will suffer this fate ... yup, it does. "The problem" isn't
yet really fixed in any version of Python, although I agree it's a lot
better with the change above.