The attached patch (create-empty-appdomain.patch) fixes bug #76757. New domains are created with only the corlib loaded, and the cross-domain code now handles the type differences correctly.

An important thing to note about this patch is that it disables a lot of code in mono/metadata/marshal.c relating to the fast cross-domain wrappers. Much of that code made bad assumptions about the availability of types in other domains and the ability to make equality comparisons by pointers. The patch forces all cross-domain calls to go through the CrossAppDomainChannel, which has also been fixed in this regard.

The attached marshal.diff shows another strategy I thought about taking. This tries to get the cross-domain wrappers to correctly understand type equality across domains. I abandoned it because it was too much effort, but anyone interested can look at it and see what I was trying to do. That diff is based on version 1.1.13.8.

Please look at this and approve it for inclusion. I can't commit things, nor would I in this case without having someone look into #76811:

  http://bugzilla.ximian.com/show_bug.cgi?id=76811

--Brian
Index: mcs/class/corlib/System.Runtime.Remoting.Messaging/CADMessages.cs
===================================================================
--- mcs/class/corlib/System.Runtime.Remoting.Messaging/CADMessages.cs   
(revision 61823)
+++ mcs/class/corlib/System.Runtime.Remoting.Messaging/CADMessages.cs   
(working copy)
@@ -51,19 +51,19 @@
        
        internal class CADObjRef {
                ObjRef objref;
-               public int SourceDomain;
+               int _sourceDomain;
 
                public CADObjRef (ObjRef o, int sourceDomain) {
                        objref = o;
-                       SourceDomain = sourceDomain;
+                       _sourceDomain = sourceDomain;
                }
-               
-               public string TypeName {
-                       get { return objref.TypeInfo.TypeName; }
+
+               public ObjRef ObjRef {
+                       get { return objref; }
                }
-               
-               public string URI {
-                       get { return objref.URI; }
+
+               public int SourceDomain {
+                       get { return _sourceDomain; }
                }
        }
 
@@ -170,12 +170,8 @@
 
                        CADObjRef objref = arg as CADObjRef;
                        if (null != objref) {
-                               string typeName = string.Copy (objref.TypeName);
-                               string uri = string.Copy (objref.URI);
-                               int domid = objref.SourceDomain;
-                               
-                               ChannelInfo cinfo = new ChannelInfo (new 
CrossAppDomainData (domid));
-                               ObjRef localRef = new ObjRef (typeName, uri, 
cinfo);
+                               ChannelInfo cinfo = new ChannelInfo (new 
CrossAppDomainData (objref.SourceDomain));
+                               ObjRef localRef = new ObjRef (objref.ObjRef, 
cinfo);
                                return RemotingServices.Unmarshal (localRef);
                        }
                        
Index: mcs/class/corlib/System.Runtime.Remoting/ChangeLog
===================================================================
--- mcs/class/corlib/System.Runtime.Remoting/ChangeLog  (revision 61823)
+++ mcs/class/corlib/System.Runtime.Remoting/ChangeLog  (working copy)
@@ -1,3 +1,9 @@
+2006-06-17  Brian Crowell  <[EMAIL PROTECTED]>
+       
+       * CADMessages.cs: Fixed the use of CADObjRef. The ObjRef is capable of
+       serializing itself, so there should be no need to re-derive its
+       properties on the other end.
+
 2006-04-27  Robert Jordan  <[EMAIL PROTECTED]>
 
        * RemotingServices.cs (IsObjectOutOfAppDomain, IsObjectOutOfContext):
Index: mcs/class/corlib/System.Runtime.Remoting/TypeInfo.cs
===================================================================
--- mcs/class/corlib/System.Runtime.Remoting/TypeInfo.cs        (revision 61823)
+++ mcs/class/corlib/System.Runtime.Remoting/TypeInfo.cs        (working copy)
@@ -42,6 +42,9 @@
 
                public TypeInfo(Type type)
                {
+                       if (type == null)
+                               throw new ArgumentNullException( "type" );
+               
                        if (type.IsInterface)
                        {
                                serverType = typeof 
(MarshalByRefObject).AssemblyQualifiedName;
Index: mcs/class/corlib/System.Runtime.Remoting/ObjRef.cs
===================================================================
--- mcs/class/corlib/System.Runtime.Remoting/ObjRef.cs  (revision 61823)
+++ mcs/class/corlib/System.Runtime.Remoting/ObjRef.cs  (working copy)
@@ -65,11 +65,13 @@
                        UpdateChannelInfo();
                }
 
-               internal ObjRef (string typeName, string uri, IChannelInfo 
cinfo) 
+               internal ObjRef (ObjRef o, IChannelInfo cinfo) 
                {
-                       this.uri = uri;
+                       uri = o.uri;
+                       typeInfo = o.typeInfo;
+                       envoyInfo = o.envoyInfo;
+                       flags = o.flags;
                        channel_info = cinfo;
-                       typeInfo = new TypeInfo (Type.GetType (typeName));
                }
 
                internal ObjRef (ObjRef o, bool unmarshalAsProxy) {
Index: mono/mono/metadata/appdomain.c
===================================================================
--- mono/mono/metadata/appdomain.c      (revision 61823)
+++ mono/mono/metadata/appdomain.c      (working copy)
@@ -467,11 +467,9 @@
 MonoAppDomain *
 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, 
MonoAppDomainSetup *setup)
 {
-       MonoDomain *domain = mono_domain_get ();
        MonoClass *adclass;
        MonoAppDomain *ad;
        MonoDomain *data;
-       GSList *tmp;
        
        MONO_ARCH_SAVE_REGS;
 
@@ -496,12 +494,8 @@
 
        mono_context_init (data);
 
-       /* The new appdomain should have all assemblies loaded */
-       mono_domain_assemblies_lock (domain);
-       /*g_print ("copy assemblies from domain %p (%s)\n", domain, 
domain->friendly_name);*/
-       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next)
-               add_assemblies_to_domain (data, tmp->data, NULL);
-       mono_domain_assemblies_unlock (domain);
+       /* Load only the corlib into the new domain */
+       add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
 
        return ad;
 }
Index: mono/mono/metadata/ChangeLog
===================================================================
--- mono/mono/metadata/ChangeLog        (revision 61823)
+++ mono/mono/metadata/ChangeLog        (working copy)
@@ -1,3 +1,20 @@
+2006-06-17  Brian Crowell  <[EMAIL PROTECTED]>
+
+       * appdomain.c (ves_icall_System_AppDomain_createDomain): Only one 
assembly
+         should be present in a newly-created domain, and that's the corlib.
+         Fixes #76757. Be on the lookout for code that relies on this bug.
+         
+       * marshal.c (mono_marshal_get_xappdomain_invoke): This function and 
related
+         functions make many assumptions about the equivalence of types and 
method
+         bodies in different domains. I started to modify the code to find 
types
+         correctly, but I saw it was just easier to disable that branch and 
send
+         cross-domain calls through the normal CrossAppDomainChannel. If anyone
+         wants to attempt repairs someday, they would do well to borrow the 
type
+         comparison code from metadata.c and modify
+         mono_marshal_emit_load_domain_method to find its target by name 
instead of
+         by pointer. I started on that and you can find my proposed changes in 
the
+         mono-devel list.
+
 2006-06-15  Zoltan Varga  <[EMAIL PROTECTED]>
 
        * marshal.c (mono_ftnptr_to_delegate): Avoid allocating signature from 
mempool
Index: mono/mono/metadata/marshal.c
===================================================================
--- mono/mono/metadata/marshal.c        (revision 61823)
+++ mono/mono/metadata/marshal.c        (working copy)
@@ -15,6 +15,7 @@
 #include "metadata/tabledefs.h"
 #include "metadata/exception.h"
 #include "metadata/appdomain.h"
+#include "metadata/assembly.h"
 #include "mono/metadata/debug-helpers.h"
 #include "mono/metadata/threadpool.h"
 #include "mono/metadata/threads.h"
@@ -2766,6 +2767,7 @@
        return NULL;
 }
 
+#if UNUSED
 /* mono_marshal_xdomain_copy_out_value()
  * Copies the contents of the src instance into the dst instance. src and dst
  * must have the same type, and if they are arrays, the same size.
@@ -2828,7 +2830,9 @@
        return !method->klass->contextbound &&
                   !((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && (strcmp 
(".ctor", method->name) == 0));
 }
+#endif
 
+#if UNUSED
 static gint32
 mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push)
 {
@@ -3137,6 +3141,7 @@
 
        return res;
 }
+#endif
 
 /* mono_marshal_get_xappdomain_invoke ()
  * Generates a fast remoting wrapper for cross app domain calls.
@@ -3147,14 +3152,15 @@
        MonoMethodSignature *sig;
        MonoMethodBuilder *mb;
        MonoMethod *res;
-       int i, j, complex_count, complex_out_count, copy_locals_base;
+       /* int i, j, complex_count, complex_out_count, copy_locals_base; */
+       int i, complex_count, complex_out_count;
        int *marshal_types;
        MonoClass *ret_class = NULL;
-       MonoMethod *xdomain_method;
+       /* MonoMethod *xdomain_method; */
        int ret_marshal_type = MONO_MARSHAL_NONE;
        int loc_array=0, loc_serialized_data=-1, loc_real_proxy;
        int loc_old_domainid, loc_return=0, loc_serialized_exc=0, loc_context;
-       int pos, pos_noex;
+       /* int pos, pos_noex; */
        gboolean copy_return = FALSE;
 
        g_assert (method);
@@ -3217,6 +3223,10 @@
        loc_serialized_exc = mono_mb_add_local (mb, 
&byte_array_class->byval_arg);
        loc_context = mono_mb_add_local (mb, 
&mono_defaults.object_class->byval_arg);
 
+#if UNUSED
+       /* The CrossAppDomainChannel takes care of this when it's used; 
otherwise
+          the unused code in the alternate branch below needs it */
+
        /* Save thread domain data */
 
        mono_mb_emit_icall (mb, mono_context_get);
@@ -3230,6 +3240,7 @@
        mono_mb_emit_byte (mb, CEE_BRFALSE_S);
        pos = mb->pos;
        mono_mb_emit_byte (mb, 0);
+#endif
        
        mono_mb_emit_ldarg (mb, 0);
        for (i = 0; i < sig->param_count; i++)
@@ -3237,6 +3248,8 @@
        
        mono_mb_emit_managed_call (mb, mono_marshal_get_remoting_invoke 
(method), NULL);
        mono_mb_emit_byte (mb, CEE_RET);
+
+#ifdef UNUSED
        mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
 
        /* Create the array that will hold the parameters to be serialized */
@@ -3460,6 +3473,7 @@
        }
 
        mono_mb_emit_byte (mb, CEE_RET);
+#endif
 
        res = mono_remoting_mb_create_and_cache (method, mb, sig, 
sig->param_count + 16);
        mono_mb_free (mb);
17a18
> #include "metadata/assembly.h"
2491a2493,2738
> /* The following functions are stolen from metadata.c. They have been 
> modified to consider
>  * equality based on name.
>  *
>  * Note that, especially in generic cases, these functions don't do all the 
> correct comparisons
>  * because of assumptions about pointers. These were present in the originals.
>  */
> 
> static gboolean mono_marshal_class_equal (MonoClass *, MonoClass *);
> static gboolean do_mono_marshal_type_equal (MonoType *, MonoType *);
> 
> static gboolean
> _mono_marshal_generic_class_equal (const MonoGenericClass *g1, const 
> MonoGenericClass *g2)
> {
>       int i;
> 
>       if ((g1->inst->type_argc != g2->inst->type_argc) || (g1->is_dynamic != 
> g2->is_dynamic) ||
>           (g1->inst->is_reference != g2->inst->is_reference))
>               return FALSE;
>       if (!mono_marshal_class_equal (g1->container_class, 
> g2->container_class))
>               return FALSE;
>       for (i = 0; i < g1->inst->type_argc; ++i) {
>               if (!do_mono_marshal_type_equal (g1->inst->type_argv [i], 
> g2->inst->type_argv [i]))
>                       return FALSE;
>       }
>       return TRUE;
> }
> 
> static gboolean
> mono_marshal_generic_method_equal (MonoGenericMethod *g1, MonoGenericMethod 
> *g2)
> {
>       return (g1->container == g2->container) && (g1->generic_class == 
> g2->generic_class) &&
>               (g1->inst == g2->inst);
> }
> 
> static gboolean
> mono_marshal_generic_param_equal (MonoGenericParam *p1, MonoGenericParam *p2)
> {
>       if (p1 == p2)
>               return TRUE;
>       if (p1->num != p2->num)
>               return FALSE;
> 
>       if (p1->owner == p2->owner)
>               return TRUE;
> 
>       return FALSE;
> }
> 
> static gboolean
> mono_marshal_class_equal (MonoClass *c1, MonoClass *c2)
> {
>       if (c1 == c2)
>               return TRUE;
> 
>       if (!strcmp (c1->name, c2->name))
>               return TRUE;
>               
>       if (c1->generic_class && c2->generic_class)
>               return _mono_marshal_generic_class_equal (c1->generic_class, 
> c2->generic_class);
>       if ((c1->byval_arg.type == MONO_TYPE_VAR) && (c2->byval_arg.type == 
> MONO_TYPE_VAR))
>               return mono_marshal_generic_param_equal (
>                       c1->byval_arg.data.generic_param, 
> c2->byval_arg.data.generic_param);
>       if ((c1->byval_arg.type == MONO_TYPE_MVAR) && (c2->byval_arg.type == 
> MONO_TYPE_MVAR))
>               return mono_marshal_generic_param_equal (
>                       c1->byval_arg.data.generic_param, 
> c2->byval_arg.data.generic_param);
>       if ((c1->byval_arg.type == MONO_TYPE_SZARRAY) && (c2->byval_arg.type == 
> MONO_TYPE_SZARRAY))
>               return mono_marshal_class_equal (c1->byval_arg.data.klass, 
> c2->byval_arg.data.klass);
>       return FALSE;
> }
> 
> /*
>  * mono_marshal_type_equal:
>  * @t1: a type
>  * @t2: another type
>  *
>  * Determine if @t1 and @t2 represent the same type (or close enough for 
> remoting purposes).
>  * Returns: #TRUE if @t1 and @t2 are equal.
>  */
> static gboolean
> do_mono_marshal_type_equal (MonoType *t1, MonoType *t2)
> {
>       if (t1->type != t2->type || t1->byref != t2->byref)
>               return FALSE;
> 
>       switch (t1->type) {
>       case MONO_TYPE_VOID:
>       case MONO_TYPE_BOOLEAN:
>       case MONO_TYPE_CHAR:
>       case MONO_TYPE_I1:
>       case MONO_TYPE_U1:
>       case MONO_TYPE_I2:
>       case MONO_TYPE_U2:
>       case MONO_TYPE_I4:
>       case MONO_TYPE_U4:
>       case MONO_TYPE_I8:
>       case MONO_TYPE_U8:
>       case MONO_TYPE_R4:
>       case MONO_TYPE_R8:
>       case MONO_TYPE_STRING:
>       case MONO_TYPE_I:
>       case MONO_TYPE_U:
>       case MONO_TYPE_OBJECT:
>       case MONO_TYPE_TYPEDBYREF:
>               return TRUE;
>       case MONO_TYPE_VALUETYPE:
>       case MONO_TYPE_CLASS:
>       case MONO_TYPE_SZARRAY:
>               return mono_marshal_class_equal (t1->data.klass, 
> t2->data.klass);
>       case MONO_TYPE_PTR:
>               return do_mono_marshal_type_equal (t1->data.type, 
> t2->data.type);
>       case MONO_TYPE_ARRAY:
>               if (t1->data.array->rank != t2->data.array->rank)
>                       return FALSE;
>               return mono_marshal_class_equal (t1->data.array->eklass, 
> t2->data.array->eklass);
>       case MONO_TYPE_GENERICINST:
>               return _mono_marshal_generic_class_equal (
>                       t1->data.generic_class, t2->data.generic_class);
>       case MONO_TYPE_VAR:
>               return mono_marshal_generic_param_equal (
>                       t1->data.generic_param, t2->data.generic_param);
>       case MONO_TYPE_MVAR:
>               return mono_marshal_generic_param_equal (
>                       t1->data.generic_param, t2->data.generic_param);
>       default:
>               g_error ("implement type compare for %0x!", t1->type);
>               return FALSE;
>       }
> 
>       return FALSE;
> }
> 
> /**
>  * mono_marshal_signature_equal:
>  * @sig1: a signature
>  * @sig2: another signature
>  *
>  * Determine if @sig1 and @sig2 represent the same signature, with the
>  * same number of arguments and the same types.
>  * Returns: #TRUE if @sig1 and @sig2 are equal.
>  */
> static gboolean
> mono_marshal_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature 
> *sig2)
> {
>       int i;
> 
>       if (sig1->hasthis != sig2->hasthis || sig1->param_count != 
> sig2->param_count) {
>               printf( "sig1: %s %d\nsig2: %s %d", sig1->hasthis ? "hasthis" : 
> "nohasthis",
>                       sig1->param_count, sig2->hasthis ? "hasthis" : 
> "nohasthis", sig2->param_count );
>       
>               return FALSE;
>       }
> 
>       /*
>        * We're just comparing the signatures of two methods here:
>        *
>        * If we have two generic methods `void Foo<U> (U u)' and `void Bar<V> 
> (V v)',
>        * U and V are equal here.
>        *
>        * That's what the `signature_only' argument of 
> do_mono_metadata_type_equal() is for.
>        */
> 
>       for (i = 0; i < sig1->param_count; i++) { 
>               MonoType *p1 = sig1->params[i];
>               MonoType *p2 = sig2->params[i];
>               
>               /* if (p1->attrs != p2->attrs)
>                       return FALSE;
>               */
>               if (!do_mono_marshal_type_equal (p1, p2)) {
>                       printf( "Parameter pair %d failed the check.\n", i );
>                       return FALSE;
>               }
>       }
> 
>       if (!do_mono_marshal_type_equal (sig1->ret, sig2->ret)) {
>               printf( "Return value failed the check.\n" );
>               return FALSE;
>       }
>       
>       return TRUE;
> }
> 
> static gpointer
> mono_marshal_find_domainlocal_method (MonoMethod *method)
> {
>       MonoAssembly *targetAssem;
>       MonoMethodSignature *sig;
>       MonoException *ex;
>       MonoClass *klass;
>       char *tmp;
>       int i;
> 
>       g_assert (method != NULL);
> 
>       targetAssem = mono_assembly_load 
> (&method->klass->image->assembly->aname, NULL, NULL);
> 
>       if (!targetAssem) {
>               mono_raise_exception (mono_get_exception_file_not_found 
> (mono_string_new_wrapper (method->klass->image->assembly->aname.name)));
>       }
> 
>       printf( "Resolved to assembly %s\n", targetAssem->aname.name );
>       printf( "Method in %s.%s\n", method->klass->name_space, 
> method->klass->name );
>       klass = mono_class_from_name (targetAssem->image, 
> method->klass->name_space, method->klass->name);
>       
>       if (!klass) {
>               char *tmp2;
>               printf( "Preparing TypeLoadException...\n" );
> 
>               tmp = g_strdup (method->klass->image->assembly->aname.name);
>               tmp2 = g_strdup_printf ("%s.%s", method->klass->name_space, 
> method->klass->name);
>               ex = mono_get_exception_type_load (mono_string_new_wrapper 
> (tmp2), tmp);
>               g_free (tmp);
>               g_free (tmp2);
>               
>               mono_raise_exception (ex);
>       }
>       
>       /* Scan the class's method table to find the equivalent method */
>       printf( "Scanning methods and signatures...\n" );
>       sig = signature_no_pinvoke (mono_method_signature (method));
>       mono_class_setup_methods (klass);
> 
>       for (i = 0; i < klass->method.count; i++) {
>               MonoMethod *foundMethod = klass->methods [i];
>               printf( "Checking method %d of %d (%s)\n", i + 1, 
> klass->method.count, foundMethod->name );
> 
>               if( mono_marshal_signature_equal (sig, mono_method_signature 
> (foundMethod)) )
>                       printf( "Match on signature\n" );
>               
>               if ((method->name [0] == foundMethod->name [0]) &&
>                               !strcmp (method->name, foundMethod->name) &&
>                               mono_marshal_signature_equal (sig, 
> mono_method_signature (foundMethod)) ) {
> 
>                       return mono_compile_method (foundMethod);
>               }
>       }
> 
>       tmp = g_strdup_printf( "%s.%s", method->klass->name_space, 
> method->klass->name );
>       ex = mono_get_exception_missing_method (tmp, method->name);
>       g_free (tmp);
>       
>       mono_raise_exception (ex);
> 
>       return NULL;
> }
> 
2513c2760,2762
<       mono_mb_emit_native_call (mb, csig, mono_compile_method);
---
>       mono_mb_emit_native_call (mb, csig, 
> mono_marshal_find_domainlocal_method);
> 
>       /* BJC: Not done here */
2598a2848,2858
>       /****** BJC: My additions ******/
> {
>       MonoClass *klass = mono_class_from_name( mono_defaults.corlib, 
> "System", "Console" );
>       
>       mono_mb_emit_ldstr( mb, "Target: {0}" );
>       mono_mb_emit_ldarg (mb, 0);
>       mono_mb_emit_managed_call (mb, method_rs_appdomain_target, NULL);
>       mono_mb_emit_managed_call (mb, mono_class_get_method_from_name( klass, 
> "WriteLine", 2 ), NULL);
> }
>       printf( "xdomain-wrapper, %s, %d parameters\n", method->name, 
> sig->param_count );
> 
2675a2936,2944
>       /****** BJC: My additions ******/
> {
>       MonoClass *klass = mono_class_from_name( mono_defaults.corlib, 
> "System", "Console" );
>       
>       mono_mb_emit_ldstr( mb, "Checkpoint Alpha" );
>       mono_mb_emit_byte (mb, CEE_LDNULL);
>       mono_mb_emit_managed_call (mb, mono_class_get_method_from_name( klass, 
> "WriteLine", 2 ), NULL);
> }
>       
2681a2951,2958
>       /****** BJC: My additions ******/
> {
>       MonoClass *klass = mono_class_from_name( mono_defaults.corlib, 
> "System", "Console" );
>       
>       mono_mb_emit_ldstr( mb, "Checkpoint Beta" );
>       mono_mb_emit_byte (mb, CEE_LDNULL);
>       mono_mb_emit_managed_call (mb, mono_class_get_method_from_name( klass, 
> "WriteLine", 2 ), NULL);
> }
2697a2975,2982
>       /****** BJC: My additions ******/
> {
>       MonoClass *klass = mono_class_from_name( mono_defaults.corlib, 
> "System", "Console" );
>       
>       mono_mb_emit_ldstr( mb, "Checkpoint Charlie" );
>       mono_mb_emit_byte (mb, CEE_LDNULL);
>       mono_mb_emit_managed_call (mb, mono_class_get_method_from_name( klass, 
> "WriteLine", 2 ), NULL);
> }
2744a3030,3037
>       /****** BJC: My additions ******/
> {
>       MonoClass *klass = mono_class_from_name( mono_defaults.corlib, 
> "System", "Console" );
>       
>       mono_mb_emit_ldstr( mb, "Checkpoint Delta" );
>       mono_mb_emit_byte (mb, CEE_LDNULL);
>       mono_mb_emit_managed_call (mb, mono_class_get_method_from_name( klass, 
> "WriteLine", 2 ), NULL);
> }
2882c3175
<       mono_mb_emit_native_call (mb, sig_context_get, mono_context_get);
---
> /*    mono_mb_emit_native_call (mb, sig_context_get, mono_context_get);
2884c3177
<       mono_mb_emit_stloc (mb, loc_context);
---
>       mono_mb_emit_stloc (mb, loc_context);*/
2889c3182
<       mono_mb_emit_managed_call (mb, method_needs_context_sink, NULL);
---
>       /*mono_mb_emit_managed_call (mb, method_needs_context_sink, NULL);
2892c3185
<       mono_mb_emit_byte (mb, 0);
---
>       mono_mb_emit_byte (mb, 0);*/
2899a3193,3194
> 
> #ifdef UNUSED
3123c3418
< 
---
> #endif
_______________________________________________
Mono-devel-list mailing list
[email protected]
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to