[PyObjC-svn] r2261 - in trunk/pyobjc/pyobjc-core: Modules/objc Modules/objc/test PyObjCTest
[email protected] Wed, 08 Jul 2009 06:10:17 -0500
| Newsgroups | gmane.comp.python.pyobjc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: ronaldoussoren
Date: Wed Jul 8 06:10:17 2009
New Revision: 2261
Log:
This fixes a bug reported by Dirk Stoop: when
a python object is allocated from ObjC and the
Python class implements the designated initializer
the object will get leaked.
Modified:
trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
trunk/pyobjc/pyobjc-core/Modules/objc/test/copying.m
trunk/pyobjc/pyobjc-core/PyObjCTest/test_regr.py
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m Wed Jul 8 06:10:17 2009
@@ -1221,11 +1221,8 @@
}
res = PyObject_Call(callable, arglist, NULL);
-
Py_DECREF(arglist);
- if (pyself) {
- PyObjCObject_ReleaseTransient(pyself, cookie);
- }
+
if (res == NULL) {
goto error;
}
@@ -1756,9 +1753,16 @@
}
}
+ }
+ Py_DECREF(res);
- Py_DECREF(res);
-
+ /* Do this at the end to ensure we work correctly when
+ * 'res' is 'pyself' and 'pyself' those are the only
+ * references from Python (that is, 'pyself' is a
+ * "transient" reference.
+ */
+ if (pyself) {
+ PyObjCObject_ReleaseTransient(pyself, cookie);
}
PyGILState_Release(state);
@@ -1766,6 +1770,9 @@
return;
error:
+ if (pyself) {
+ PyObjCObject_ReleaseTransient(pyself, cookie);
+ }
PyObjCErr_ToObjCWithGILState(&state);
}
@@ -2018,6 +2025,7 @@
PyObjCPythonSelector *pythonSelector = (PyObjCPythonSelector *) aSelector;
PyObjCMethodSignature* methinfo = PyObjCMethodSignature_ForSelector(
pythonSelector->sel_class,
+// (pythonSelector->sel_flags & PyObjCSelector_kCLASS_METHOD) != 0,
pythonSelector->sel_selector,
pythonSelector->sel_python_signature);
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/test/copying.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/test/copying.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/test/copying.m Wed Jul 8 06:10:17 2009
@@ -13,6 +13,7 @@
@interface OC_CopyHelper : NSObject
{ }
+(NSObject*)doCopySetup:(Class)aClass;
++(NSObject*)newObjectOfClass:(Class)aClass;
@end
@implementation OC_CopyHelper
@@ -28,6 +29,10 @@
[tmp release];
return retval;
}
++(NSObject*)newObjectOfClass:(Class)aClass
+{
+ return [[aClass alloc] init];
+}
@end
@interface OC_CopyBase : NSObject <NSCopying>
Modified: trunk/pyobjc/pyobjc-core/PyObjCTest/test_regr.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/PyObjCTest/test_regr.py (original)
+++ trunk/pyobjc/pyobjc-core/PyObjCTest/test_regr.py Wed Jul 8 06:10:17 2009
@@ -1,9 +1,10 @@
from PyObjCTools.TestSupport import *
from PyObjCTest import structargs
from PyObjCTest import testbndl
+from PyObjCTest import copying
import objc, sys
-from PyObjCTest.fnd import NSObject
+from PyObjCTest.fnd import NSObject, NSAutoreleasePool
rct = structargs.StructArgClass.someRect.__metadata__()['retval']['type']
@@ -150,5 +151,68 @@
p = self.AlignmentTestClass.alloc().init()
self.assertEquals(p.testWithObject_(o) % 16, o.stackPtr() % 16)
+
+
+#
+# Regression in retainCount management when a Python object
+# is created from Objective-C. This only happened when the
+# Python class has an implementation of the designated initializer.
+#
+# Mentioned by Dirk Stoop on the Pyobjc-dev mailing-list.
+#
+
+gDeallocCounter = 0
+class OC_LeakTest_20090704_init (NSObject):
+ def init(self):
+ #self = super(OC_LeakTest_20090704_init, self).init()
+ return self
+
+ def dealloc(self):
+ global gDeallocCounter
+ gDeallocCounter += 1
+
+class OC_LeakTest_20090704_noinit (NSObject):
+ def dealloc(self):
+ global gDeallocCounter
+ gDeallocCounter += 1
+
+
+class TestInitMemoryLeak (TestCase):
+ def testNoPythonInit(self):
+ # This test is basicly a self-test of the test-case, the
+ # test even passed before the regression was fixed.
+
+ global gDeallocCounter
+
+ pool = NSAutoreleasePool.alloc().init()
+ try:
+ v = copying.OC_CopyHelper.newObjectOfClass_(OC_LeakTest_20090704_noinit)
+ self.failUnlessIsInstance(v, OC_LeakTest_20090704_noinit)
+
+ gDeallocCounter = 0
+ del v
+
+ finally:
+ del pool
+
+ self.failIfEqual(gDeallocCounter, 0)
+
+ def testWithPythonInit(self):
+ global gDeallocCounter
+
+ pool = NSAutoreleasePool.alloc().init()
+ try:
+ v = copying.OC_CopyHelper.newObjectOfClass_(OC_LeakTest_20090704_init)
+ self.failUnlessIsInstance(v, OC_LeakTest_20090704_init)
+
+ gDeallocCounter = 0
+ del v
+
+ finally:
+ del pool
+
+ self.failIfEqual(gDeallocCounter, 0)
+
+
if __name__ == '__main__':
main()
------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge
This is your chance to win up to $100,000 in prizes! For a limited time,
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize
details at: http://p.sf.net/sfu/Challenge