strange thing after call PyObject_CallMethod

E

Exe

Hello everybody!

I'm in trouble. This code shows that ob_refcnt increased by python
if "on_recv" method throws exception. This occurs only if base C-class
subclassed
in python code.
======
my_old_refcnt = Py_REFCNT(self);
py_result = PyObject_CallMethod(self, "on_recv", "(y#)", recvbuf, result);
my_new_refcnt = Py_REFCNT(self);

log_debug("refcnt before call %d", my_old_refcnt);
log_debug("after call: %d\n", my_new_refcnt);
======


Output:
======
tcpconn.c: refcnt before call 1
tcpconn.c: after call: 2
======

If PyObject_CallMethod returns success(any non-NULL value) anything okay.
Tested on Python 3.1a0 (py3k:68145M, Jan 2 2009, 20:51:28).

Why this happenning and who makes Py_INCREF(self)?


PS garbage collector knows about this so on exit
PyGC_Collect deletes instance.
 
M

Martin v. Löwis

Why this happenning and who makes Py_INCREF(self)?

There are multiple possible explanations, but I think you
have ruled out most of them:

1. on_recv might be returning self. So py_result would be
the same as self, and hence be an additional reference.
However, you said that on_recv raised an exception, so
py_result should be NULL (can you confirm?)

2. there might be a reference leak in the implementation of
on_recv. However, you say that it is all fine at the
end, so this is unlikely

3. The implementation of on_recv stores the object inside
another objects. There are too many possibilities for that
to enumerate; here are some examples:

def on_recv(self, buf):
global foo, bar
foo = self # creates global reference
bar = self.on_send # creates bound method
self.foo = self # creates cyclic reference
foobar.append(self) # adds self into container

If you are using gdb, I recommend to set a watchpoint on
changes to ob_refcnt:

(gdb) p &((PyObject*)self)->ob_refcnt
$1 = (Py_ssize_t *) 0xa0cb5a0
(gdb) watch *(Py_ssize_t *) 0xa0cb5a0
Hardware watchpoint 2: *(ssize_t *) 168605088
(gdb) c
Continuing.
Hardware watchpoint 2: *(ssize_t *) 168605088

Old value = 2
New value = 1
0xb7d5f406 in list_clear (a=0xa041c74) at Objects/listobject.c:550
550 Py_XDECREF(item);

As you can see: this specific object was stored in a list, and
the list is now being cleared.

HTH,
Martin
 
B

Bug Hunter

Thank you for so amazing debugging tutorial :).
I owe you a beer.

I found source of problem: then unhandled in python code
exception occurs frame_dealloc() (Objects/frameobject.c:422)
not called. Even if I call PyErr_Print().

But! If I call PyErr_Clear() then all okay!
Docs says that both this functions clears error indicator...
I hit a bug or my brains overheated?

Some gdb output if you are intrested:
Without exception: http://dpaste.com/104973/
With exception: http://dpaste.com/104975/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top