Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mono/metadata/cominterop.c53
-rw-r--r--mono/tests/cominterop.cs52
2 files changed, 85 insertions, 20 deletions
diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c
index 9ec1d0f10c3..d0e2241063c 100644
--- a/mono/metadata/cominterop.c
+++ b/mono/metadata/cominterop.c
@@ -173,6 +173,31 @@ typedef struct {
MonoCCW* ccw;
} MonoCCWInterface;
+/*
+ * COM Callable Wrappers
+ *
+ * CCWs may be called on threads that aren't attached to the runtime, they can
+ * then run managed code or the method implementations may use coop handles.
+ * Use the macros below to setup the thread state.
+ *
+ * For managed methods, the runtime marshaling wrappers handle attaching and
+ * coop state switching.
+ */
+
+#define MONO_CCW_CALL_ENTER do { \
+ gpointer dummy; \
+ gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy); \
+ MONO_ENTER_GC_UNSAFE; \
+ HANDLE_FUNCTION_ENTER (); \
+ do {} while (0)
+
+#define MONO_CCW_CALL_EXIT \
+ HANDLE_FUNCTION_RETURN (); \
+ MONO_EXIT_GC_UNSAFE; \
+ mono_threads_detach_coop (orig_domain, &dummy); \
+ } while (0)
+
+
/* IUnknown */
static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
@@ -2568,12 +2593,9 @@ static int STDCALL
cominterop_ccw_addref (MonoCCWInterface* ccwe)
{
int result;
- gpointer dummy;
- gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
- MONO_ENTER_GC_UNSAFE;
+ MONO_CCW_CALL_ENTER;
result = cominterop_ccw_addref_impl (ccwe);
- MONO_EXIT_GC_UNSAFE;
- mono_threads_detach_coop (orig_domain, &dummy);
+ MONO_CCW_CALL_EXIT;
return result;
}
@@ -2602,12 +2624,9 @@ static int STDCALL
cominterop_ccw_release (MonoCCWInterface* ccwe)
{
int result;
- gpointer dummy;
- gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
- MONO_ENTER_GC_UNSAFE;
+ MONO_CCW_CALL_ENTER;
result = cominterop_ccw_release_impl (ccwe);
- MONO_EXIT_GC_UNSAFE;
- mono_threads_detach_coop (orig_domain, &dummy);
+ MONO_CCW_CALL_EXIT;
return result;
}
@@ -2654,12 +2673,9 @@ static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
{
int result;
- gpointer dummy;
- gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
- MONO_ENTER_GC_UNSAFE;
+ MONO_CCW_CALL_ENTER;
result = cominterop_ccw_queryinterface_impl (ccwe, riid, ppv);
- MONO_EXIT_GC_UNSAFE;
- mono_threads_detach_coop (orig_domain, &dummy);
+ MONO_CCW_CALL_EXIT;
return result;
}
@@ -2777,12 +2793,9 @@ cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
guint32 lcid, gint32 *rgDispId)
{
int result;
- gpointer dummy;
- gpointer orig_domain = mono_threads_attach_coop (mono_domain_get(), &dummy);
- MONO_ENTER_GC_UNSAFE;
+ MONO_CCW_CALL_ENTER;
result = cominterop_ccw_get_ids_of_names_impl (ccwe, riid, rgszNames, cNames, lcid, rgDispId);
- MONO_EXIT_GC_UNSAFE;
- mono_threads_detach_coop (orig_domain, &dummy);
+ MONO_CCW_CALL_EXIT;
return result;
}
diff --git a/mono/tests/cominterop.cs b/mono/tests/cominterop.cs
index 11cb68bcdbc..3ff018efa71 100644
--- a/mono/tests/cominterop.cs
+++ b/mono/tests/cominterop.cs
@@ -659,6 +659,9 @@ public class Tests
}
}
+ if (CallableWrapperLeakTest () != 0)
+ return 209;
+
#endregion // COM Callable Wrapper Tests
#region SAFEARRAY tests
@@ -1630,6 +1633,55 @@ public class Tests
return 2;
return 0;
}
+
+ // Doesn't matter what this is
+ internal class CallableWrapperLeakTestClass {
+ }
+
+ public static int CallableWrapperLeakTest () {
+ bool ok = true;
+ GCHandle h = HideFromGC (() => {
+ var o = new CallableWrapperLeakTestClass();
+ var weakHandle = GCHandle.Alloc (o, GCHandleType.Weak);
+ var pUnk = Marshal.GetIUnknownForObject (o);
+ int c = Marshal.Release(pUnk);
+ o = null;
+ if (c != 0) {
+ Console.Error.WriteLine ("Expected IUnknown refcount on a CCW to be 0 after Release, was {0}", c);
+ ok = false;
+ }
+ return weakHandle;
+ });
+ if (!ok)
+ return 1;
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ HideFromGC(() => {
+ var o = h.Target;
+ if (o != null) {
+ Console.Error.WriteLine ("Expected weak handle to be null after GC, but the object (of type {0}) was retained", o.GetType());
+ ok = false;
+ }
+ return "done"; // doesn't matter
+ });
+ if (!ok)
+ return 2;
+ return 0;
+ }
+
+ [MethodImpl (MethodImplOptions.NoInlining)]
+ private static T HideFromGC<T> (Func<T> f) => HideFromGC (20, f);
+
+ [MethodImpl (MethodImplOptions.NoInlining)]
+ private static T HideFromGC<T> (int rec, Func<T> f) {
+ if (rec <= 0)
+ return f ();
+ else
+ return HideFromGC (rec - 1, f);
+ }
+
}
public class TestVisible