Commits

Ronald Oussoren  committed a749da0

A (partial?) fix for bug 1206669.

This changes the generic IMP to not -retain self unless the Python proxy will
stay alive when the IMP returns. This patch passes all unittests (including
the one I added earlier today), but I haven't tested using real applications
yet.

  • Participants
  • Parent commits 04722f0
  • Branches pyobjc-ancient

Comments (0)

Files changed (4)

File Modules/objc/libffi_support.m

 	PyObject*          v;
 	int                have_output = 0;
 	const char*        rettype;
+	PyObject* pyself;
+#define UNINIT
+#ifdef UNINIT
+	int		didCreate = 0;
+#endif
 
 	PyGILState_STATE   state = PyGILState_Ensure();
 
 	}
 
 	arglist = PyList_New(0);
-	v = pythonify_c_value(@encode(id), args[0+argOffset]);
-	if (v == NULL) {
+
+#ifndef UNINIT
+	pyself = pythonify_c_value(@encode(id), args[0+argOffset]);
+#else
+	/* just calling pythonify_c_value is not not correct: we should
+	 * try to avoid calling -retain because this can cause problems is
+	 * self is freshly +alloc-ed and this is a call to the initializer
+	 *
+	 * It is 99+% sure that self won't be treated specially by 
+	 * pythonify_c_value, it is extremely unlikely that anyone want's to
+	 * subclass a class that is treated specially by that function.
+	 */
+	pyself = PyObjC_FindPythonProxy(*(id*)args[0+argOffset]);
+	if (pyself == NULL) {
+		/* This is a bit of a hack, should drop NewXXX() and add
+		 * some arguments to New()
+		 */
+		pyself = PyObjCObject_NewUnitialized(*(id*)args[0+argOffset]);
+
+		((PyObjCObject*)pyself)->flags |= PyObjCObject_kSHOULD_NOT_RELEASE;
+		((PyObjCObject*)pyself)->flags &= ~PyObjCObject_kUNINITIALIZED;
+		didCreate = 1;
+	}
+
+#endif
+	if (pyself == NULL) {
 		goto error;
 	}
-	if (PyList_Append(arglist, v) == -1) {
+	if (PyList_Append(arglist, pyself) == -1) {
 		goto error;
 	}
-	Py_DECREF(v);
+	Py_DECREF(pyself);
 
 	/* First translate from Objective-C to python */
 	
 	res = PyObject_Call(callable, arglist, NULL);
 	isAlloc = PyObjCSelector_DonatesRef(callable);
 
+#ifdef UNINIT
+	if (pyself->ob_refcnt != 1 && didCreate) {
+		/* Oops, additional references to the proxy, make sure we
+		 * own a reference to the ObjC object
+		 */
+		[PyObjCObject_GetObject(pyself) retain];
+		((PyObjCObject*)pyself)->flags &= ~PyObjCObject_kUNINITIALIZED;
+	}
+#endif
 	Py_DECREF(arglist);
 	if (res == NULL) {
 		goto error;

File Modules/objc/objc-object.h

 
 #define PyObjCObject_kUNINITIALIZED 	0x01
 #define PyObjCObject_kCLASSIC 		0x02
-#define PyObjCObject_kDEALLOC_HELPER	0x03
+#define PyObjCObject_kDEALLOC_HELPER	0x04
+#define PyObjCObject_kSHOULD_NOT_RELEASE      0x08
 typedef struct {
 	PyObject_HEAD
 	id        objc_object;

File Modules/objc/objc-object.m

 		if (PyObjCObject_IsClassic(obj)) {
 			/* pass */
 
+		} else if ((((PyObjCObject*)obj)->flags
+				& PyObjCObject_kSHOULD_NOT_RELEASE)) {
+			/* pass */
+
 		} else if (((PyObjCObject*)obj)->flags 
 				& PyObjCObject_kUNINITIALIZED) {
 			/* Freeing of an uninitialized object, just leak because 
 	PyObjCClass_CheckMethodList((PyObject*)res->ob_type, 1);
 	
 	((PyObjCObject*)res)->objc_object = objc_object;
-	((PyObjCObject*)res)->flags = 0;
+	/*((PyObjCObject*)res)->flags = 0;*/
+	((PyObjCObject*)res)->flags = PyObjCObject_kUNINITIALIZED;
 
 	PyObjC_RegisterPythonProxy(objc_object, res);
 

File Modules/objc/selector.m

 			 * too high
 			 */
 			id obj = PyObjCObject_GetObject(pyres);
+
 			[obj release];
 		}
 	}
 	     ((PyObjCObject*)self->sel_self)->flags & PyObjCObject_kUNINITIALIZED) {
 
 	     ((PyObjCObject*)self->sel_self)->flags &= ~PyObjCObject_kUNINITIALIZED;
+
 	}
 
 	return result;