Commits

Ronald Oussoren  committed bcd3800

Fix reference counting in wrappers for plain python objects.

  • Participants
  • Parent commits e9d51c9
  • Branches pyobjc-ancient

Comments (0)

Files changed (2)

File Lib/Foundation/test/test_nstimer.py

+import unittest
+import gc
+
+from objc import *
+from Foundation import *
+
+class PythonClass (object):
+    def __init__(self):
+        self.fireCount = 0
+
+    def fire_(self, timer):
+        self.fireCount += 1
+
+
+class TestNSTimer(unittest.TestCase):
+
+    def _testHelp(self):
+        obj = PythonClass()
+        pool = NSAutoreleasePool.new()
+        timer = NSTimer.timerWithTimeInterval_target_selector_userInfo_repeats_(
+                0.1, obj, 'fire:', None, False)
+        NSRunLoop.currentRunLoop().addTimer_forMode_(
+                timer, NSDefaultRunLoopMode)
+        NSRunLoop.currentRunLoop().runUntilDate_(
+                NSDate.dateWithTimeIntervalSinceNow_(0.2))
+        timer.invalidate()
+        self.assertEquals(obj.fireCount, 1)
+
+        del timer
+        del pool
+
+    def testPythonLeakage(self):
+
+        # Ignore first run, this has some side-effects that would
+        # taint the result.
+        self._testHelp()
+
+        # Now run the test again in a loop to detect leakage
+        gc.collect()
+        before = len(gc.get_objects())
+
+        for i in range(10):
+            self._testHelp()
+
+        gc.collect()
+        after = len(gc.get_objects())
+
+        self.assertEquals(after, before)
+
+if __name__ == '__main__':
+    unittest.main( )

File Modules/objc/OC_PythonObject.m

 			return pymethod;
 		}
 	} 
+
 	return NULL;
 }
 
 	unsigned int argcount;
 	PyObject*    pymethod;
 	const char*  p;
+	PyObject*    result;
 
 	if (!aSelector) {
 		[NSException raise:NSInvalidArgumentException
 		return NULL;	
 	}
 
-	return check_argcount(pymethod, argcount);
+	result =  check_argcount(pymethod, argcount);
+	if (result == NULL) {
+		Py_DECREF(pymethod);
+	}
+	return result;
 }
 
 
 		m = get_method_for_selector(pyObject, aSelector);
 
 		if (m) {
+			Py_DECREF(m);
 			PyObjC_GIL_RETURN(YES);
 		} else {
 			PyErr_Clear();
 				pymethod);
 			argcount = func_code->co_argcount;
 		}
+		Py_DECREF(pymethod);
 
 		encoding = alloca(argcount+4);
 		memset(encoding, '@', argcount+3);
 		argcount = [msign numberOfArguments];
 		args = PyTuple_New(argcount-2);
 		if (args == NULL) {
+			Py_DECREF(pymethod);
 			PyObjC_GIL_FORWARD_EXC();
 		}
 		for (i=2; i< argcount; i++) {
 
 			argsize = PyObjCRT_SizeOfType(argtype);
 			if (argsize == -1) {
+				Py_DECREF(args);
+				Py_DECREF(pymethod);
 				PyObjC_GIL_FORWARD_EXC();
 			}
 			argbuffer = alloca (argsize);
 			pyarg = pythonify_c_value (argtype, argbuffer);
 			if (pyarg == NULL) {
 				Py_DECREF(args);
+				Py_DECREF(pymethod);
 				PyObjC_GIL_FORWARD_EXC();
 			}
 
 			PyTuple_SET_ITEM (args, i-2, pyarg);
 		}
 		result = PyObject_CallObject(pymethod, args);
-		Py_DECREF(args);
+		Py_DECREF(args); args = NULL;
+		Py_DECREF(pymethod); pymethod = NULL;
 
 		if (result == NULL) {
 			PyObjC_GIL_FORWARD_EXC();
 		}
 
 		err = depythonify_c_value (rettype, result, retbuffer);
+		Py_DECREF(result);
 		if (err == -1) {
 			PyObjC_GIL_FORWARD_EXC();
 		} else {