Subject: | memory leaks and segfaults |
Inline::Python is 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, thus the fix for the memleak is
commented out in the patch.
Subject: | Inline-Python-segfaults-memleaks.diff |
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;
}