2010-03-03 Marek Habersack <mhabersack@novell.com>
authorMarek Habersack <grendel@twistedcode.net>
Wed, 3 Mar 2010 14:16:14 +0000 (14:16 -0000)
committerMarek Habersack <grendel@twistedcode.net>
Wed, 3 Mar 2010 14:16:14 +0000 (14:16 -0000)
* mono-config.c (mono_config_parse_assembly_bindings): added -
parses assembly binding redirections from appdomain's config
file.

* metadata-internals.h: added definition of a new function -
mono_config_parse_assembly_bindings - to support parsing assembly
binding redirections defined in appdomain's config file.

* domain-internals.h: added two new fields to _MonoDomain - a list
of assembly bindings and a flag to parse the config file only
once.

* assembly.c (assembly_binding_maps_name): empty culture name and
NULL culture name are considered equal.
(mono_assembly_apply_binding): added support for domain specific
assembly binding redirections, read from the appdomain's
configuration file. Fixes bug #580185

svn path=/trunk/mono/; revision=152931

mono/metadata/ChangeLog
mono/metadata/assembly.c
mono/metadata/domain-internals.h
mono/metadata/domain.c
mono/metadata/metadata-internals.h
mono/metadata/mono-config.c

index faca5e21fef844e18c6ecac4d2f29dbba8a7be7a..b039a25dda25e4c5b7a02fb48fe922c08abcec9d 100644 (file)
@@ -1,3 +1,22 @@
+2010-03-03  Marek Habersack  <mhabersack@novell.com>
+
+       * mono-config.c (mono_config_parse_assembly_bindings): added -
+       parses assembly binding redirections from appdomain's config
+       file.
+
+       * metadata-internals.h: added definition of a new function -
+       mono_config_parse_assembly_bindings - to support parsing assembly
+       binding redirections defined in appdomain's config file.
+
+       * domain-internals.h: added two new fields to _MonoDomain - a list
+       of assembly bindings and a flag to parse the config file only
+       once.
+
+       * assembly.c (assembly_binding_maps_name): empty culture name and
+       NULL culture name are considered equal.
+       (mono_assembly_apply_binding): added support for domain specific
+       assembly binding redirections, read from the appdomain's
+       configuration file. Fixes bug #580185
 
 Wed Mar 3 11:46:06 CET 2010 Paolo Molaro <lupus@ximian.com>
 
index fb694b1ff8f5a7329e36c6e11f6e2c3d24aaed19..fa9b304f1575e9b81eadb1ecef9bc462ef9b5561 100644 (file)
@@ -233,13 +233,16 @@ check_extra_gac_path_env (void) {
 static gboolean
 assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
 {
+       if (!info || !info->name)
+               return FALSE;
+
        if (strcmp (info->name, aname->name))
                return FALSE;
 
        if (info->major != aname->major || info->minor != aname->minor)
                return FALSE;
 
-       if ((info->culture != NULL) != (aname->culture != NULL))
+       if ((info->culture != NULL && info->culture [0]) != (aname->culture != NULL && aname->culture [0])) 
                return FALSE;
        
        if (info->culture && strcmp (info->culture, aname->culture))
@@ -254,6 +257,9 @@ assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *ana
 static void
 mono_assembly_binding_info_free (MonoAssemblyBindingInfo *info)
 {
+       if (!info)
+               return;
+
        g_free (info->name);
        g_free (info->culture);
 }
@@ -2225,17 +2231,135 @@ search_binding_loaded (MonoAssemblyName *aname)
        return NULL;
 }
 
+static inline gboolean
+info_compare_versions (AssemblyVersionSet *left, AssemblyVersionSet *right)
+{
+       if (left->major != right->major || left->minor != right->minor ||
+           left->build != right->build || left->revision != right->revision)
+               return FALSE;
+
+       return TRUE;
+}
+
+static inline gboolean
+info_versions_equal (MonoAssemblyBindingInfo *left, MonoAssemblyBindingInfo *right)
+{
+       if (left->has_old_version_bottom != right->has_old_version_bottom)
+               return FALSE;
+
+       if (left->has_old_version_top != right->has_old_version_top)
+               return FALSE;
+
+       if (left->has_new_version != right->has_new_version)
+               return FALSE;
+
+       if (left->has_old_version_bottom && !info_compare_versions (&left->old_version_bottom, &right->old_version_bottom))
+               return FALSE;
+
+       if (left->has_old_version_top && !info_compare_versions (&left->old_version_top, &right->old_version_top))
+               return FALSE;
+
+       if (left->has_new_version && !info_compare_versions (&left->new_version, &right->new_version))
+               return FALSE;
+
+       return TRUE;
+}
+
+/* LOCKING: assumes all the necessary locks are held */
+static void
+assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
+{
+       MonoAssemblyBindingInfo *info_copy;
+       GSList *tmp;
+       MonoAssemblyBindingInfo *info_tmp;
+       MonoDomain *domain = (MonoDomain*)user_data;
+
+       if (!domain)
+               return;
+
+       for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
+               info_tmp = tmp->data;
+               if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
+                       return;
+       }
+
+       info_copy = mono_mempool_alloc0 (domain->mp, sizeof (MonoAssemblyBindingInfo));
+       memcpy (info_copy, info, sizeof (MonoAssemblyBindingInfo));
+       if (info->name)
+               info_copy->name = mono_mempool_strdup (domain->mp, info->name);
+       if (info->culture)
+               info_copy->culture = mono_mempool_strdup (domain->mp, info->culture);
+
+       domain->assembly_bindings = g_slist_append_mempool (domain->mp, domain->assembly_bindings, info_copy);
+}
+
+static inline gboolean
+info_major_minor_in_range (MonoAssemblyBindingInfo *info, MonoAssemblyName *aname)
+{
+       if (!info->has_old_version_bottom)
+               return FALSE;
+
+       if (info->old_version_bottom.major > aname->major || info->old_version_bottom.minor > aname->minor)
+               return FALSE;
+
+       if (info->has_old_version_top && (info->old_version_top.major < aname->major || info->old_version_top.minor < aname->minor))
+               return FALSE;
+
+       /* This is not the nicest way to do it, but it's a by-product of the way parsing is done */
+       info->major = aname->major;
+       info->minor = aname->minor;
+
+       return TRUE;
+}
+
+/* LOCKING: Assumes that we are already locked - both loader and domain locks */
+static MonoAssemblyBindingInfo*
+get_per_domain_assembly_binding_info (MonoDomain *domain, MonoAssemblyName *aname)
+{
+       MonoAssemblyBindingInfo *info;
+       GSList *list;
+
+       if (!domain->assembly_bindings)
+               return NULL;
+
+       info = NULL;
+       for (list = domain->assembly_bindings; list; list = list->next) {
+               info = list->data;
+               if (info && !strcmp (aname->name, info->name) && info_major_minor_in_range (info, aname))
+                       break;
+               info = NULL;
+       }
+
+       if (info) {
+               if (info->name && info->public_key_token [0] && info->has_old_version_bottom &&
+                   info->has_new_version && assembly_binding_maps_name (info, aname))
+                       info->is_valid = TRUE;
+               else
+                       info->is_valid = FALSE;
+       }
+
+       return info;
+}
+
 static MonoAssemblyName*
 mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_name)
 {
        MonoAssemblyBindingInfo *info, *info2;
        MonoImage *ppimage;
+       MonoDomain *domain;
 
        if (aname->public_key_token [0] == 0)
                return aname;
 
+       domain = mono_domain_get ();
        mono_loader_lock ();
        info = search_binding_loaded (aname);
+       if (!info) {
+               mono_domain_lock (domain);
+               info = get_per_domain_assembly_binding_info (domain, aname);
+               mono_domain_unlock (domain);
+       }
+
        mono_loader_unlock ();
        if (info) {
                if (!check_policy_versions (info, aname))
@@ -2245,14 +2369,36 @@ mono_assembly_apply_binding (MonoAssemblyName *aname, MonoAssemblyName *dest_nam
                return dest_name;
        }
 
-       info = g_new0 (MonoAssemblyBindingInfo, 1);
-       info->major = aname->major;
-       info->minor = aname->minor;
-       
-       ppimage = mono_assembly_load_publisher_policy (aname);
-       if (ppimage) {
-               get_publisher_policy_info (ppimage, aname, info);
-               mono_image_close (ppimage);
+       if (domain && domain->setup && domain->setup->configuration_file) {
+               mono_domain_lock (domain);
+               if (!domain->assembly_bindings_parsed) {
+                       gchar *domain_config_file = mono_string_to_utf8 (domain->setup->configuration_file);
+
+                       mono_config_parse_assembly_bindings (domain_config_file, aname->major, aname->minor, domain, assembly_binding_info_parsed);
+                       domain->assembly_bindings_parsed = TRUE;
+                       g_free (domain_config_file);
+               }
+               mono_domain_unlock (domain);
+
+               mono_loader_lock ();
+               mono_domain_lock (domain);
+               info = get_per_domain_assembly_binding_info (domain, aname);
+               mono_domain_unlock (domain);
+               mono_loader_unlock ();
+       }
+
+       if (!info) {
+               info = g_new0 (MonoAssemblyBindingInfo, 1);
+               info->major = aname->major;
+               info->minor = aname->minor;
+       }
+
+       if (!info->is_valid) {
+               ppimage = mono_assembly_load_publisher_policy (aname);
+               if (ppimage) {
+                       get_publisher_policy_info (ppimage, aname, info);
+                       mono_image_close (ppimage);
+               }
        }
 
        /* Define default error value if needed */
index 26ea5cde7ec2b1a401b7befcb8d0630c265d2b17..b552319ce5464ac23087b7a9c29ff66a02750530 100644 (file)
@@ -12,6 +12,7 @@
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-internal-hash.h>
 #include <mono/io-layer/io-layer.h>
+#include <mono/metadata/mempool-internals.h>
 
 extern CRITICAL_SECTION mono_delegate_section;
 extern CRITICAL_SECTION mono_strtod_mutex;
@@ -269,6 +270,10 @@ struct _MonoDomain {
 
        /* Contains the compiled method used by async resylt creation to capture thread context*/
        gpointer            capture_context_method;
+
+       /* Assembly bindings, the per-domain part */
+       GSList *assembly_bindings;
+       gboolean assembly_bindings_parsed;
 };
 
 typedef struct  {
index fd700f9b8ae4f999cf9365362fdf69f5db36aa52..2a433ddf29541cc9491b22e65d78804e7c52122d 100644 (file)
@@ -1186,6 +1186,8 @@ mono_domain_create (void)
        domain->code_mp = mono_code_manager_new ();
        domain->env = mono_g_hash_table_new_type ((GHashFunc)mono_string_hash, (GCompareFunc)mono_string_equal, MONO_HASH_KEY_VALUE_GC);
        domain->domain_assemblies = NULL;
+       domain->assembly_bindings = NULL;
+       domain->assembly_bindings_parsed = FALSE;
        domain->class_vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        domain->proxy_vtable_hash = g_hash_table_new ((GHashFunc)mono_ptrarray_hash, (GCompareFunc)mono_ptrarray_equal);
        domain->static_data_array = NULL;
index e5ee576802b2cec79152d0612fd7a2b5b6114a6e..2b9af74d039431aa9c3d37c2275448168fd3918e 100644 (file)
@@ -611,6 +611,8 @@ void mono_assembly_close_finish (MonoAssembly *assembly) MONO_INTERNAL;
 gboolean mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2) MONO_INTERNAL;
 
 void mono_config_parse_publisher_policy (const char *filename, MonoAssemblyBindingInfo *binding_info) MONO_INTERNAL;
+void mono_config_parse_assembly_bindings (const char *filename, int major, int minor, void *user_data,
+                                         void (*infocb)(MonoAssemblyBindingInfo *info, void *user_data)) MONO_INTERNAL;
 
 gboolean
 mono_assembly_name_parse_full               (const char           *name,
index 3ab16b78975cdd449eb8cd2e1ff5f56ca877169f..50e2702acbd1f6bb13bf20a292ef6dc90bdff9a2 100644 (file)
@@ -144,6 +144,12 @@ struct MonoParseHandler {
        void (*finish) (gpointer user_data);
 };
 
+typedef struct {
+       MonoAssemblyBindingInfo *info;
+       void (*info_parsed)(MonoAssemblyBindingInfo *info, void *user_data);
+       void *user_data;
+} ParserUserData;
+
 typedef struct {
        MonoParseHandler *current;
        void *user_data;
@@ -592,17 +598,43 @@ mono_get_machine_config (void)
        return bundled_machine_config;
 }
 
+static void
+assembly_binding_end (gpointer user_data, const char *element_name)
+{
+       ParserUserData *pud = user_data;
+
+       if (!strcmp (element_name, "dependentAssembly")) {
+               if (pud->info_parsed && pud->info) {
+                       pud->info_parsed (pud->info, pud->user_data);
+                       g_free (pud->info->name);
+                       g_free (pud->info->culture);
+               }
+       }
+}
+
 static void
 publisher_policy_start (gpointer user_data,
                const gchar *element_name,
                const gchar **attribute_names,
                const gchar **attribute_values)
 {
+       ParserUserData *pud;
        MonoAssemblyBindingInfo *info;
        int n;
 
-       info = user_data;
-       if (!strcmp (element_name, "assemblyIdentity")) {
+       pud = user_data;
+       info = pud->info;
+       if (!strcmp (element_name, "dependentAssembly")) {
+               info->name = NULL;
+               info->culture = NULL;
+               info->has_old_version_bottom = FALSE;
+               info->has_old_version_top = FALSE;
+               info->has_new_version = FALSE;
+               info->is_valid = FALSE;
+               memset (&info->old_version_bottom, 0, sizeof (info->old_version_bottom));
+               memset (&info->old_version_top, 0, sizeof (info->old_version_top));
+               memset (&info->new_version, 0, sizeof (info->new_version));
+       } if (!strcmp (element_name, "assemblyIdentity")) {
                for (n = 0; attribute_names [n]; n++) {
                        const gchar *attribute_name = attribute_names [n];
                        
@@ -706,9 +738,14 @@ publisher_policy_parser = {
 void
 mono_config_parse_publisher_policy (const gchar *filename, MonoAssemblyBindingInfo *info)
 {
+       ParserUserData user_data = {
+               info,
+               NULL,
+               NULL
+       };
        ParseState state = {
                &publisher_policy_parser, /* MonoParseHandler */
-               info, /* user_data */
+               &user_data, /* user_data */
                NULL, /* MonoImage (we don't need it right now)*/
                TRUE /* We are already inited */
        };
@@ -716,3 +753,35 @@ mono_config_parse_publisher_policy (const gchar *filename, MonoAssemblyBindingIn
        mono_config_parse_file_with_context (&state, filename);
 }
 
+static MonoParseHandler
+config_assemblybinding_parser = {
+       "", /* We don't need to use declare an xml element */
+       NULL,
+       publisher_policy_start,
+       NULL,
+       assembly_binding_end,
+       NULL
+};
+
+void
+mono_config_parse_assembly_bindings (const char *filename, int amajor, int aminor, void *user_data, void (*infocb)(MonoAssemblyBindingInfo *info, void *user_data))
+{
+       MonoAssemblyBindingInfo info = {
+               .major = amajor,
+               .minor = aminor
+       };
+       ParserUserData pud = {
+               &info,
+               infocb,
+               user_data
+       };
+       ParseState state = {
+               &config_assemblybinding_parser, /* MonoParseHandler */
+               &pud, /* user_data */
+               NULL, /* MonoImage (we don't need it right now)*/
+               TRUE /* We are already inited */
+       };
+
+       mono_config_parse_file_with_context (&state, filename);
+}
+