Skip to content

Commit

Permalink
2010-03-03 Marek Habersack <mhabersack@novell.com>
Browse files Browse the repository at this point in the history
	* 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
  • Loading branch information
grendello committed Mar 3, 2010
1 parent 49d2fda commit 0dd75d3
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 12 deletions.
19 changes: 19 additions & 0 deletions mono/metadata/ChangeLog
@@ -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>

Expand Down
164 changes: 155 additions & 9 deletions mono/metadata/assembly.c
Expand Up @@ -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))
Expand All @@ -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);
}
Expand Down Expand Up @@ -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))
Expand All @@ -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 */
Expand Down
5 changes: 5 additions & 0 deletions mono/metadata/domain-internals.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions mono/metadata/domain.c
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions mono/metadata/metadata-internals.h
Expand Up @@ -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,
Expand Down
75 changes: 72 additions & 3 deletions mono/metadata/mono-config.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -706,13 +738,50 @@ 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 */
};

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);
}

0 comments on commit 0dd75d3

Please sign in to comment.