Hi! Sending this mail to the inline-mailing list, since [EMAIL PROTECTED] doesn't seem to be a valid address anymore.
I'm trying to use Inline::Python in a web application for compatibility with huge amounts of legacy Python code. I've gotten pretty far and it works well, but it's leaking memory like pretty much all objects one moves from perl to Python space. I've fixed a bug where a perl object is freed when it's still in use, three memory leaks and a segfault that surfaced when some destructors finally got called, but there are still more segfaults seemingly unrelated to the code I changed and I'm not even sure if I cought all memory leaks. What I've found so far: PerlObj_dealloc should use sv_2mortal instead of SvREFCNT_dec, because the perl object could be a return value and thus still be in use. py_call_function and py_call_method both do not free the return value if called in void context and they only free the constructed argument tuple if a Python error occured, but not if everything worked. After fixing that PerlSub_dealloc segfaulted because of uninitialized member variables (sub, pkg and full). Py2Pl should sv_2mortal the newly created Inline::Python::Object. Otherwise it's refcnt would be 2 for a call like: my $obj = Inline::Python::Object->new('__main__', 'MyClass'); Unfortunately this creates a segfault in py_call_method in my application. Haven't tracked this down yet. This is my first real encounter with either Perl's or Python's internals, so it could be, that I'm completely mistaken about all this. But I think, I'm on the right track. Nonetheless I would be very, very glad to find someone still interested in maintaining this module and in my fixes and maybe give a little support on my mission. To be frank I'm not sure anymore if I can fix this alone. It seems like a bottomless pit of wrong refcnts and trying to keep them all right is clearly expanding my mind... With kind regards, Stefan Seifert
diff -aur Inline-Python-0.22-mqoigh/Python.xs Inline-Python-0.22/Python.xs --- Inline-Python-0.22-mqoigh/Python.xs 2004-07-27 07:02:05.000000000 +0200 +++ Inline-Python-0.22/Python.xs 2008-08-29 22:18:39.000000000 +0200 @@ -213,12 +213,13 @@ } Printf(("calling func\n")); py_retval = PyObject_CallObject(func, tuple); + Py_XDECREF(func); +// Py_XDECREF(tuple); //FIXME: obviously correct, but causes segfault on second reload Printf(("received a response\n")); if (!py_retval || (PyErr_Occurred() != NULL)) { fprintf(stderr,"Error: Python error occurred:\n"); PyErr_Print(); - Py_XDECREF(tuple); - Py_XDECREF(func); + Py_XDECREF(tuple); //FIXME: should not be done only on errors croak("Error -- PyObject_CallObject(...) failed.\n"); XSRETURN_EMPTY; } @@ -234,8 +235,10 @@ /* For whatever reason, GIMME_V always returns G_VOID when we get forwarded * from eval_python(). */ - if (GIMME_V == G_VOID) + if (GIMME_V == G_VOID) { + Py_DECREF(py_retval); XSRETURN_EMPTY; + } #endif Printf(("calling Py2Pl\n")); @@ -321,11 +324,11 @@ Printf(("calling func\n")); py_retval = PyObject_CallObject(method, tuple); + Py_DECREF(tuple); + Py_DECREF(method); Printf(("received a response\n")); if (!py_retval || (PyErr_Occurred() != NULL)) { PyErr_Print(); - Py_DECREF(tuple); - Py_DECREF(method); croak("PyObject_CallObject(...) failed.\n"); XSRETURN_EMPTY; } @@ -333,8 +336,10 @@ Printf(("no error\n")); #ifdef CHECK_CONTEXT /* We can save a little time by checking our context */ - if (GIMME_V == G_VOID) + if (GIMME_V == G_VOID) { + Py_DECREF(py_retval); XSRETURN_EMPTY; + } #endif Printf(("calling Py2Pl()\n")); diff -aur Inline-Python-0.22-mqoigh/perlmodule.c Inline-Python-0.22/perlmodule.c --- Inline-Python-0.22-mqoigh/perlmodule.c 2001-12-10 06:18:09.000000000 +0100 +++ Inline-Python-0.22/perlmodule.c 2008-08-29 21:52:52.000000000 +0200 @@ -203,7 +203,7 @@ PerlObj_dealloc(PerlObj_object *self) { Py_XDECREF(self->pkg); - if (self->obj) SvREFCNT_dec(self->obj); + if (self->obj) sv_2mortal(self->obj); // mortal instead of DECREF. Object might be return value PyMem_DEL(self); } @@ -301,6 +301,11 @@ self->pkg = package; self->full = PyString_FromString(str); } + else { + self->sub = NULL; + self->pkg = NULL; + self->full = NULL; + } /* we don't have to check for errors because we shouldn't have been * created unless perl_get_cv worked once. diff -aur Inline-Python-0.22-mqoigh/py2pl.c Inline-Python-0.22/py2pl.c --- Inline-Python-0.22-mqoigh/py2pl.c 2005-01-10 07:19:33.000000000 +0100 +++ Inline-Python-0.22/py2pl.c 2008-08-29 22:02:28.000000000 +0200 @@ -102,6 +102,9 @@ re-bless it */ Py_INCREF(obj); Printf(("Py2Pl: Instance\n")); + /* this should be correct, but I get segfaults on method calls + with it :( */ + // sv_2mortal(inst_ptr); return inst_ptr; }