[runtime] Fix bug when marshaling COM interfaces in arrays
authorDamien Daspit <damien_daspit@sil.org>
Thu, 17 Nov 2016 03:47:47 +0000 (10:47 +0700)
committerEberhard Beilharz <eb1@sil.org>
Tue, 8 Aug 2017 21:18:23 +0000 (17:18 -0400)
* use the correct COM interface when creating native array
* do not free CCWs when freeing the native array

This fixes Xamarin-47560.

mono/metadata/cominterop.c
mono/metadata/cominterop.h
mono/metadata/marshal.c

index d522657b62f0b97efa9792ba77734e29d2882e12..d57cb52796be252c94d86cffbbc96db8bab7167c 100644 (file)
@@ -3664,3 +3664,52 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
 {
        mono_free_bstr (ptr);
 }
+
+void*
+mono_cominterop_get_com_interface (MonoObject *object, MonoClass *ic, MonoError *error)
+{
+       error_init (error);
+
+#ifndef DISABLE_COM
+       if (!object)
+               return NULL;
+
+       if (cominterop_object_is_rcw (object)) {
+               MonoClass *klass = NULL;
+               MonoRealProxy* real_proxy = NULL;
+               if (!object)
+                       return NULL;
+               klass = mono_object_class (object);
+               if (!mono_class_is_transparent_proxy (klass)) {
+                       mono_error_set_invalid_operation (error, "Class is not transparent");
+                       return NULL;
+               }
+
+               real_proxy = ((MonoTransparentProxy*)object)->rp;
+               if (!real_proxy) {
+                       mono_error_set_invalid_operation (error, "RealProxy is null");
+                       return NULL;
+               }
+
+               klass = mono_object_class (real_proxy);
+               if (klass != mono_class_get_interop_proxy_class ()) {
+                       mono_error_set_invalid_operation (error, "Object is not a proxy");
+                       return NULL;
+               }
+
+               if (!((MonoComInteropProxy*)real_proxy)->com_object) {
+                       mono_error_set_invalid_operation (error, "Proxy points to null COM object");
+                       return NULL;
+               }
+
+               void* com_itf = cominterop_get_interface_checked (((MonoComInteropProxy*)real_proxy)->com_object, ic, error);
+               return com_itf;
+       }
+       else {
+               void* ccw_entry = cominterop_get_ccw_checked (object, ic, error);
+               return ccw_entry;
+       }
+#else
+       g_assert_not_reached ();
+#endif
+}
index fc0e00297708d5b612828f629f18d806b9d7d291..04abc6e5fab1015ee3698302894f9f4abd5ac1b1 100644 (file)
@@ -64,4 +64,7 @@ mono_free_bstr (gpointer bstr);
 MonoClass*
 mono_class_try_get_com_object_class (void);
 
+void*
+mono_cominterop_get_com_interface (MonoObject* object, MonoClass* ic, MonoError *error);
+
 #endif /* __MONO_COMINTEROP_H__ */
index 1cca5a3c74330ca22a25e06e98d69f951b972f74..5eb477a909673e92570f65c3437810468448dc0d 100644 (file)
@@ -799,12 +799,13 @@ mono_array_to_lparray (MonoArray *array)
 
        int i = 0;
        MonoClass *klass;
+       MonoError error;
 #endif
 
        if (!array)
                return NULL;
 #ifndef DISABLE_COM
-
+       error_init (&error);
        klass = array->obj.vtable->klass;
 
        switch (klass->element_class->byval_arg.type) {
@@ -814,8 +815,11 @@ mono_array_to_lparray (MonoArray *array)
        case MONO_TYPE_CLASS:
                nativeArraySize = array->max_length;
                nativeArray = (void **)malloc(sizeof(gpointer) * nativeArraySize);
-               for(i = 0; i < nativeArraySize; ++i)    
-                       nativeArray[i] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((MonoObject **)array->vector)[i]);
+               for(i = 0; i < nativeArraySize; ++i) {
+                       nativeArray[i] = mono_cominterop_get_com_interface (((MonoObject **)array->vector)[i], klass->element_class, &error);
+                       if (mono_error_set_pending_exception (&error))
+                               break;
+               }
                return nativeArray;
        case MONO_TYPE_U1:
        case MONO_TYPE_BOOLEAN:
@@ -853,7 +857,6 @@ mono_free_lparray (MonoArray *array, gpointer* nativeArray)
 {
 #ifndef DISABLE_COM
        MonoClass *klass;
-       int i = 0;
 
        if (!array)
                return;
@@ -862,11 +865,8 @@ mono_free_lparray (MonoArray *array, gpointer* nativeArray)
                return;
        klass = array->obj.vtable->klass;
 
-       if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS) {
-               for(i = 0; i < array->max_length; ++i)
-                       mono_marshal_free_ccw (mono_array_get (array, MonoObject*, i));
+       if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS)
                g_free (nativeArray);
-       }
 #endif
 }