On Fri, Jul 18, 2008 at 2:41 PM, Charles R Harris <charlesr.harris@gmail.com> wrote:
<snip>

There are actually two bugs here which is confusing things.

Bug 1) Deleting a numpy scalar doesn't decrement the descr reference count.
Bug 2) PyArray_Return decrements the reference to arr, which in turn correctly decrements the descr on gc.

So calls that go through the default (obj == NULL) correctly leave typecode with a reference, it just never gets decremented when the return object is deleted.

On the other hand, if the function is called with something like float32(0), then arr is allocated, stealing a reference to typecode. PyArray_Return then deletes arr (which decrements the typecode reference), but that doesn't matter since typecode is a singleton. In this case there is no follow on stack dump when the returned object is deleted because the descr reference is not correctly decremented.

BTW, both cases get returned in the first if statement after the finish label, i.e., robj is returned.

Oy, what a mess.

Here is a short program to follow all the reference counts.

import sys, gc
import numpy as np

def main() :
    typecodes = "?bBhHiIlLqQfdgFDG"
    for typecode in typecodes :
        t = np.dtype(typecode)
        refcnt = sys.getrefcount(t)
        t.type()
        gc.collect()
        print typecode, t.name, sys.getrefcount(t) - refcnt

if __name__ == "__main__" :
    main()

Which gives the following output:

$[charris@f8 ~]$ python debug.py
? bool 0
b int8 1
B uint8 1
h int16 1
H uint16 1
i int32 0
I uint32 1
l int32 0
L uint32 1
q int64 1
Q uint64 1
f float32 1
d float64 0
g float96 1
F complex64 1
D complex128 1
G complex192 1

Note that the python types, which the macro handles, don't have the reference leak problem.

Chuck