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;
 	}
 

Reply via email to