Julian Rüth schrieb am 23.02.22 um 04:46:
> We identified a method [1] that
> is causing the trouble. Strangely, if we just change this method from cpdef
> to def without any changes elsewhere, the problem disappears.
What this changes is the way the method is *called* in other places. It now
becomes a C method, into which callers pass their arguments as straight C
values instead of a Python argument tuple (and keywords). This also means
that the Python object arguments are not kept alive by an argument tuple,
and that you need to make sure that an argument does not get deallocated
while the method is running and working with it. This can happen, for
example, when you pass an argument directly from an attribute of a cdef
class. Although I think there are guards for this case now that would
internally keep the reference alive. Still, there may be cases where this
can't be assured internally, so worth finding out.
> And printing the sys.getrefcount of the objects
> involved appears to confirm that the refcount is not updated correctly when
> coming back from a cpdef call [4] in some cases.
I would a) check if the method changes any state (i.e. replaces any
references) in the outside world, and b) look at the callers to see if they
depend on that state. If so, make sure that you keep a live reference
manually. Specifically, find out where the arguments "x" and "y" are coming
from.
> Unfortunately, we have not been able yet to create a simple reproducer for
> this issue. Looking at the generated C code, we find that the cpdef method
> has one additional DECREF in its exception handling block [2] that the def
> method does not have [3].
That's unrelated. It simply uses more temporary variables internally
because it needs to additionally handle the case that the method gets
called directly as a C method, but then detects that it's actually in a
subclass that has overwritten the method as a Python method, and that it
needs to call that instead. So it generates code to calls the Python method.
Is that something you do here, BTW? Overwrite the cpdef method with a def
method in a (Python) subclass?
Stefan