From 6d626a24a7979abc43b3848caa29aa7a1f614ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20G=2E=20Aragoneses?= Date: Wed, 17 Jul 2013 14:24:02 +0200 Subject: [PATCH] glib: avoid a delegate to be GCed which caused a NRE (bxc#13113) What seemed to be a race condition (because of not happenning 100% of the times) ended up being an early garbage collection of a delegate that was still referenced by an unmanaged struct without having a managed counterpart [1]. The consequence of this was a NullReferenceException happening in a line which didn't have a dereference of a null object. The way to reproduce it deterministically 100% of the times was setting the env var MONO_NO_SMP. [1] http://www.mono-project.com/Interop_with_Native_Libraries#Memory_Boundaries --- glib/GType.cs | 13 +++++++------ glib/Object.cs | 4 +++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/glib/GType.cs b/glib/GType.cs index 46be4df89..b236dd41c 100755 --- a/glib/GType.cs +++ b/glib/GType.cs @@ -1,9 +1,11 @@ // GLib.Type.cs - GLib GType class implementation // -// Author: Mike Kestner +// Authors: Mike Kestner +// Andres G. Aragoneses // // Copyright (c) 2003 Mike Kestner // Copyright (c) 2003 Novell, Inc. +// Copyright (c) 2013 Andres G. Aragoneses // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the Lesser GNU General @@ -36,11 +38,10 @@ namespace GLib { IntPtr val; + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + internal delegate void ClassInitDelegate (IntPtr gobject_class_handle); + struct GTypeInfo { - - [UnmanagedFunctionPointer (CallingConvention.Cdecl)] - public delegate void ClassInitDelegate (IntPtr gobject_class_handle); - public ushort class_size; public IntPtr base_init; public IntPtr base_finalize; @@ -371,7 +372,7 @@ namespace GLib { GTypeInfo info = new GTypeInfo (); info.class_size = (ushort) query.class_size; info.instance_size = (ushort) query.instance_size; - info.class_init = gobject_class_initializer.ClassInit; + info.class_init = gobject_class_initializer.ClassInitManagedDelegate; GType gtype = new GType (g_type_register_static (parent_gtype.Val, native_name, ref info, 0)); GLib.Marshaller.Free (native_name); diff --git a/glib/Object.cs b/glib/Object.cs index 19604f9e4..b3a3be040 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -188,6 +188,7 @@ namespace GLib { internal Type Type { get; private set; } internal bool HandlersOverriden { get; private set; } + internal GType.ClassInitDelegate ClassInitManagedDelegate { get; private set; } uint idx = 1; bool is_first_subclass; @@ -196,6 +197,7 @@ namespace GLib { internal ClassInitializer (Type type) { + ClassInitManagedDelegate = this.ClassInit; Type = type; gtype = GType.RegisterGObjectType (this); is_first_subclass = gtype.GetBaseType () == gtype.GetThresholdType (); @@ -231,7 +233,7 @@ namespace GLib { } } - internal void ClassInit (IntPtr gobject_class_handle) + private void ClassInit (IntPtr gobject_class_handle) { bool override_ctor = is_first_subclass;