Python Improvement Idea: Singleton protection

Warren Postma embed at NOSPAM.geocities.com
Wed Aug 16 09:52:42 EDT 2000


[subject was formerly "How to find who is decref'ing Py_None on me!"]

> Quoth warren orignally:
> > I have an embedded/extended Python App in which the reference
> > counts on Py_None are creeping towards zero during program run,
> > and I'd like to find which DECREFs are causing it. ...

> Quoth "Tim":
> FWIW, it's almost certainly *not* the case that someone is decref'ing
> Py_None when they shouldn't, so looking at DECREFs is likely to give you
an
> excruciatingly long tour of correctly-working code.  Far more likely is
that
> one of your functions is returning Py_None but neglecting to INCREF it
> first.  In which case, there's no need to look at the Python
implementation
> at all:  look at the return paths in your own code.


Here is the Stupid Thing I did:

PyObject *MYExtension_MyMethod(PyObject *self,  PyObject *args)
{
  PyObject *result;

    // DO SOME STUFF HERE.
    // ...
    //  Call something else that returns a variety of different kinds of
objects:
    result = DoSomething(...);
    //  Handle all kinds of different results in all kinds of different
ways:
    if (!HandleResult(result))
    {  ERR_MSG_RETURN_NULL("blah blah blah");
    };

    // Now the stupid person (me) who wrote HandleResult forgets he
    // already decref'd the result before he returns,
    // making the next decref an additional one:

    Py_DECREF(result); // Really Bad Mistake here but it took me days to
find my stupidity.
    return result;
}


So, with all that code in there, I was def-reffing Py_None twice in my code.

It seemeth to me that there ought to be a better way to track these things.
Since Py_None is of the Nothing type, and is the Only Nothing In the System
(Singleton), couldn't a global flag called "PySingletonProtection" be set to
1, and if the destructor of the Nothing Type is invoked, it would raise an
exception there, rather than having the system blow up later due to the
hard-to-track problem of having 500+ references to a destroyed PyNone object
around?

So, when Python is finished initialization, the PySingletonProtection global
would be set to 1, and when PyFinalize is called, it would be cleared.  Then
if any attempt to delete the one, the only, every buddhist's favourite
instance of Non-ado, an exception befitting the crime could be raised.  Any
thoughts anyone?

Other singletons should include the built-in instances of small Integers
that are created when the system starts, the empty list [], the empty tuple
(), and all other "the system won't run without it" type of singletons, and
so on.  I believe the lowest overhead method would be to add checks to the
destructors of the type.   If anyone is interested in me prototyping this
based on the 1.5 or 1.6 source code, I will go ahead and do it, but if
anyone can shoot this down as a bad idea, I'd also like to know about it.
I'm not proposing anything that would add to the size of all PyObjects, only
a few lines of code in the destructors of certain built in Types, so that
things that Py_DECREF is not allowed to free after Python is initialized,
and before we enter PyFinalize. This code could even be conditionally
compiled in for debug builds of Python only.

Anyone else think this is handy? In the case of my bug above, the exception
would eventually be raised at the line marked "bad news" above.

Warren






More information about the Python-list mailing list