[Python-Dev] Preserving the blamelist

Tim Peters tim.peters at gmail.com
Wed Apr 12 19:43:43 CEST 2006


[Tim]
>> Phillip, when eyeballing gen_dealloc(), I didn't understand two things:
>>
>> 1. Why doesn't
>>
>>         if (gen->gi_frame->f_stacktop!=NULL) {
>>
>>    check first to be sure that gen->gi_frame != Py_None?

[Phillip]
> Apparently, it's because I'm an idiot, and because nobody else realized
> this during the initial review of the patch.  :)

Then you were the bold adventurer, and the reviewers were the idiots ;-)

>> Is that impossible here for some reason?

> No, I goofed.  It's amazing that this doesn't dump core whenever a
> generator exits.  :(

Well, it's extremely likely that &((PyGenObject *)Py_None)->f_stacktop
is a legit part of the process address space, so that dereferencing is
non-problematic. We just read up nonsense then, test against it, and
the conditional

		gen->ob_type->tp_del(self);

is harmless as gen_del() returns at once (because it does check for
Py_None right away -- we never try to treat gi_frame->f_stacktop _as_
a frame pointer here, we just check it against NULL).  If we have to
have insane code, harmlessly insane is the best kind :--)

>> 2. It _looks_ like "gi_frame != NULL" is an (undocumented) invariant.
>>    Right?  If so,
>>
>>         Py_XDECREF(gen->gi_frame);
>>
>>    sends a confusing message (because of the "X", implying that NULL is OK).
>>    Regardless, it would be good to add comments to genobject.h explaining
>>    the possible values gi_frame can hold.  For example, what does it mean
>>    when gi_frame is Py_None?  Can it ever be NULL?

> I think what happened is that at one point I thought I was going to set
> gi_frame=NULL when there's no active frame, in order to speed up
> reclamation of the frame.  However, I think I then thought that it would
> break the operation of the generator's 'gi_frame' attribute, which is
> defined as T_OBJECT.

That shouldn't be a problem:  when PyMember_GetOne() fetches a
T_OBJECT that's NULL, it returns (a properly incref'ed) Py_None
instead.

> Or else I thought that the tp_visit was screwed up in that case.
>
> So, it looks to me like what this *should* do is simply allow gi_frame to
> be NULL instead of Py_None, which would get rid of all the silly casting,
> and retroactively make the XDECREF correct.  :)

That indeed sounds better to me, although you still don't get out of
writing gi_frame comments for genobject.h :-)

> Does gen_traverse() need to do anything special to visit a null
> pointer?  Should it only conditionally visit it?

The body of gen_traverse() is best written:

    Py_VISIT(gen->gi_frame);
    return 0;

Py_VISIT is defined in objimpl.h, and takes care of NULLs and
exceptional returns.

BTW, someone looking for an easy task might enjoy rewriting other
tp_traverse slots to use Py_VISIT.  We even have cases now (like
super_traverse) where modules define their own workalike
traverse-visit macros, which has become confusing since a standard
macro was defined for this purpose.


More information about the Python-Dev mailing list