Merge pull request #4453 from lambdageek/bug-49721
[mono.git] / mono / metadata / assembly.c
index 643c4930b1a29360e4c80fc4cae1df1cf51da0bf..aa900409470e52ba1c0b1d51e3ed2ca1608d7215 100644 (file)
@@ -22,6 +22,7 @@
 #include "object-internals.h"
 #include <mono/metadata/loader.h>
 #include <mono/metadata/tabledefs.h>
+#include <mono/metadata/custom-attrs-internals.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/class-internals.h>
@@ -29,7 +30,6 @@
 #include <mono/metadata/reflection-internals.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/mono-debug.h>
-#include <mono/io-layer/io-layer.h>
 #include <mono/utils/mono-uri.h>
 #include <mono/metadata/mono-config.h>
 #include <mono/metadata/mono-config-dirs.h>
@@ -76,8 +76,13 @@ static char **assemblies_path = NULL;
 static char **extra_gac_paths = NULL;
 
 #ifndef DISABLE_ASSEMBLY_REMAPPING
+
+static GHashTable* assembly_remapping_table;
 /* The list of system assemblies what will be remapped to the running
- * runtime version. WARNING: this list must be sorted.
+ * runtime version.
+ * This list is stored in @assembly_remapping_table during initialization.
+ * Keep it sorted just to make maintenance easier.
+ *
  * The integer number is an index in the MonoRuntimeInfo structure, whose
  * values can be found in domain.c - supported_runtimes. Look there
  * to understand what remapping will be made.
@@ -133,18 +138,29 @@ static const AssemblyVersionMap framework_assemblies [] = {
        {"System.Drawing", 0},
        {"System.Drawing.Design", 0},
        {"System.EnterpriseServices", 0},
+       {"System.IO.Compression", 2},
        {"System.IdentityModel", 3},
        {"System.IdentityModel.Selectors", 3},
        {"System.Management", 0},
        {"System.Messaging", 0},
        {"System.Net", 2},
+       {"System.Net.Http", 4},
+       {"System.Numerics.Vectors", 3},
+       {"System.Runtime.InteropServices.RuntimeInformation", 2},
        {"System.Runtime.Remoting", 0},
        {"System.Runtime.Serialization", 3},
+       {"System.Runtime.Serialization.Formatters", 3},
        {"System.Runtime.Serialization.Formatters.Soap", 0},
        {"System.Security", 0},
        {"System.ServiceModel", 3},
+       {"System.ServiceModel.Duplex", 3},
+       {"System.ServiceModel.Http", 3},
+       {"System.ServiceModel.NetTcp", 3},
+       {"System.ServiceModel.Primitives", 3},
+       {"System.ServiceModel.Security", 3},
        {"System.ServiceModel.Web", 2},
        {"System.ServiceProcess", 0},
+       {"System.Text.Encoding.CodePages", 3},
        {"System.Transactions", 0},
        {"System.Web", 0},
        {"System.Web.Abstractions", 2},
@@ -156,6 +172,8 @@ static const AssemblyVersionMap framework_assemblies [] = {
        {"System.Windows.Forms", 0},
        {"System.Xml", 0},
        {"System.Xml.Linq", 2},
+       {"System.Xml.ReaderWriter", 3},
+       {"System.Xml.XPath.XmlDocument", 3},
        {"WindowsBase", 3},
        {"mscorlib", 0}
 };
@@ -204,9 +222,7 @@ static mono_mutex_t assembly_binding_mutex;
 static GSList *loaded_assembly_bindings = NULL;
 
 /* Class lazy loading functions */
-static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, System.Runtime.CompilerServices, InternalsVisibleToAttribute)
-static GENERATE_TRY_GET_CLASS_WITH_CACHE (reference_assembly, System.Runtime.CompilerServices, ReferenceAssemblyAttribute)
-
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (internals_visible, "System.Runtime.CompilerServices", "InternalsVisibleToAttribute")
 static MonoAssembly*
 mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
 static MonoAssembly*
@@ -214,6 +230,9 @@ mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *request
 static MonoBoolean
 mono_assembly_is_in_gac (const gchar *filanem);
 
+static MonoAssembly*
+prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly);
+
 static gchar*
 encode_public_tok (const guchar *token, gint32 len)
 {
@@ -509,7 +528,7 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
 }
 
 static MonoAssembly *
-load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly)
+load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
 {
        int i;
        char *fullpath;
@@ -517,7 +536,7 @@ load_in_path (const char *basename, const char** search_path, MonoImageOpenStatu
 
        for (i = 0; search_path [i]; ++i) {
                fullpath = g_build_filename (search_path [i], basename, NULL);
-               result = mono_assembly_open_full (fullpath, status, refonly);
+               result = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, status);
                g_free (fullpath);
                if (result)
                        return result;
@@ -567,7 +586,7 @@ mono_assembly_getrootdir (void)
  * Returns: a string with the directory, this string should be freed by
  * the caller.
  */
-G_CONST_RETURN gchar *
+gchar *
 mono_native_getrootdir (void)
 {
        gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
@@ -782,6 +801,15 @@ mono_assemblies_init (void)
 
        mono_os_mutex_init_recursive (&assemblies_mutex);
        mono_os_mutex_init (&assembly_binding_mutex);
+
+#ifndef DISABLE_ASSEMBLY_REMAPPING
+       assembly_remapping_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+       int i;
+       for (i = 0; i < G_N_ELEMENTS (framework_assemblies) - 1; ++i)
+               g_hash_table_insert (assembly_remapping_table, (void*)framework_assemblies [i].assembly_name, (void*)&framework_assemblies [i]);
+
+#endif
 }
 
 static void
@@ -797,7 +825,7 @@ mono_assembly_binding_unlock (void)
 }
 
 gboolean
-mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
+mono_assembly_fill_assembly_name_full (MonoImage *image, MonoAssemblyName *aname, gboolean copyBlobs)
 {
        MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
        guint32 cols [MONO_ASSEMBLY_SIZE];
@@ -811,7 +839,11 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
        aname->hash_len = 0;
        aname->hash_value = NULL;
        aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
+       if (copyBlobs)
+               aname->name = g_strdup (aname->name);
        aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
+       if (copyBlobs)
+               aname->culture = g_strdup (aname->culture);
        aname->flags = cols [MONO_ASSEMBLY_FLAGS];
        aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
        aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
@@ -842,6 +874,16 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
 
        if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
                aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
+               if (copyBlobs) {
+                       const gchar *pkey_end;
+                       int len = mono_metadata_decode_blob_size ((const gchar*) aname->public_key, &pkey_end);
+                       pkey_end += len; /* move to end */
+                       size_t size = pkey_end - (const gchar*)aname->public_key;
+                       guchar *tmp = g_new (guchar, size);
+                       memcpy (tmp, aname->public_key, size);
+                       aname->public_key = tmp;
+               }
+
        }
        else
                aname->public_key = 0;
@@ -874,6 +916,12 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
        return TRUE;
 }
 
+gboolean
+mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
+{
+       return mono_assembly_fill_assembly_name_full (image, aname, FALSE);
+}
+
 /**
  * mono_stringify_assembly_name:
  * @aname: the assembly name.
@@ -1003,7 +1051,6 @@ static MonoAssemblyName *
 mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname)
 {
        const MonoRuntimeInfo *current_runtime;
-       int pos, first, last;
 
        if (aname->name == NULL) return aname;
 
@@ -1040,52 +1087,62 @@ mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_ana
        }
        
 #ifndef DISABLE_ASSEMBLY_REMAPPING
-       first = 0;
-       last = G_N_ELEMENTS (framework_assemblies) - 1;
-       
-       while (first <= last) {
-               int res;
-               pos = first + (last - first) / 2;
-               res = strcmp (aname->name, framework_assemblies[pos].assembly_name);
-               if (res == 0) {
-                       const AssemblyVersionSet* vset;
-                       int index = framework_assemblies[pos].version_set_index;
-                       g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
-                       vset = &current_runtime->version_sets [index];
-
-                       if (aname->major == vset->major && aname->minor == vset->minor &&
-                               aname->build == vset->build && aname->revision == vset->revision)
-                               return aname;
-               
-                       if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
-                               return aname;
-
-                       if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
-                               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
-                                       "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
-                                                       aname->name,
-                                                       aname->major, aname->minor, aname->build, aname->revision,
-                                                       vset->major, vset->minor, vset->build, vset->revision
-                                                       );
-                       
-                       memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
-                       dest_aname->major = vset->major;
-                       dest_aname->minor = vset->minor;
-                       dest_aname->build = vset->build;
-                       dest_aname->revision = vset->revision;
-                       if (framework_assemblies[pos].new_assembly_name != NULL) {
-                               dest_aname->name = framework_assemblies[pos].new_assembly_name;
-                               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
-                                                       "The assembly name %s was remapped to %s",
-                                                       aname->name,
-                                                       dest_aname->name);
-                       }
-                       return dest_aname;
-               } else if (res < 0) {
-                       last = pos - 1;
-               } else {
-                       first = pos + 1;
+       const AssemblyVersionMap *vmap = (AssemblyVersionMap *)g_hash_table_lookup (assembly_remapping_table, aname->name);
+       if (vmap) {
+               const AssemblyVersionSet* vset;
+               int index = vmap->version_set_index;
+               g_assert (index < G_N_ELEMENTS (current_runtime->version_sets));
+               vset = &current_runtime->version_sets [index];
+
+               if (aname->major == vset->major && aname->minor == vset->minor &&
+                       aname->build == vset->build && aname->revision == vset->revision) {
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Found assembly remapping for %s and was for the same version %d.%d.%d.%d",
+                               aname->name,
+                               aname->major, aname->minor, aname->build, aname->revision);
+                       return aname;
+               }
+
+               if (vmap->only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0) {
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY,
+                               "Found lower-versions-only assembly remaping to load %s %d.%d.%d.%d but mapping has %d.%d.%d.%d",
+                                               aname->name,
+                                               aname->major, aname->minor, aname->build, aname->revision,
+                                               vset->major, vset->minor, vset->build, vset->revision
+                                               );
+                       return aname;
                }
+
+               if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
+                       mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
+                               "The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
+                                               aname->name,
+                                               aname->major, aname->minor, aname->build, aname->revision,
+                                               vset->major, vset->minor, vset->build, vset->revision
+                                               );
+
+               memcpy (dest_aname, aname, sizeof(MonoAssemblyName));
+               dest_aname->major = vset->major;
+               dest_aname->minor = vset->minor;
+               dest_aname->build = vset->build;
+               dest_aname->revision = vset->revision;
+               if (current_runtime->public_key_token != NULL &&
+                   dest_aname->public_key_token [0] != 0 &&
+                   !mono_public_tokens_are_equal (dest_aname->public_key_token, (const mono_byte *)current_runtime->public_key_token)) {
+                       mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
+                                   "The request for assembly name '%s' with PublicKeyToken=%s was remapped to PublicKeyToken=%s",
+                                   dest_aname->name,
+                                   dest_aname->public_key_token,
+                                   current_runtime->public_key_token);
+                       memcpy (dest_aname->public_key_token, current_runtime->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+               }
+               if (vmap->new_assembly_name != NULL) {
+                       dest_aname->name = vmap->new_assembly_name;
+                       mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
+                                               "The assembly name %s was remapped to %s",
+                                               aname->name,
+                                               dest_aname->name);
+               }
+               return dest_aname;
        }
 #endif
 
@@ -1208,6 +1265,7 @@ mono_assembly_load_reference (MonoImage *image, int index)
                                   aname.major, aname.minor, aname.build, aname.revision,
                                   strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
                g_free (extra_msg);
+
        }
 
        mono_assemblies_lock ();
@@ -1224,7 +1282,7 @@ mono_assembly_load_reference (MonoImage *image, int index)
                                    image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
                } else {
                        if (image->assembly)
-                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p]\n",
+                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s[%p].",
                                    image->assembly->aname.name, image->assembly);
                }
                
@@ -1622,6 +1680,22 @@ mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *statu
  */
 MonoAssembly *
 mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
+{
+       return mono_assembly_open_a_lot (filename, status, refonly, FALSE);
+}
+
+MonoAssembly *
+mono_assembly_open_a_lot (const char *filename, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
+{
+       return mono_assembly_open_predicate (filename, refonly, load_from_context, NULL, NULL, status);
+}
+
+MonoAssembly *
+mono_assembly_open_predicate (const char *filename, gboolean refonly,
+                             gboolean load_from_context,
+                             MonoAssemblyCandidatePredicate predicate,
+                             gpointer user_data,
+                             MonoImageOpenStatus *status)
 {
        MonoImage *image;
        MonoAssembly *ass;
@@ -1698,7 +1772,7 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo
        }
 
        if (!image)
-               image = mono_image_open_full (fname, status, refonly);
+               image = mono_image_open_a_lot (fname, status, refonly, load_from_context);
 
        if (!image){
                if (*status == MONO_IMAGE_OK)
@@ -1715,7 +1789,7 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo
                return image->assembly;
        }
 
-       ass = mono_assembly_load_from_full (image, fname, status, refonly);
+       ass = mono_assembly_load_from_predicate (image, fname, refonly, predicate, user_data, status);
 
        if (ass) {
                if (!loaded_from_bundle)
@@ -1764,7 +1838,7 @@ mono_assembly_load_friends (MonoAssembly* ass)
        if (ass->friend_assembly_names_inited)
                return;
 
-       attrs = mono_custom_attrs_from_assembly_checked (ass, &error);
+       attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
        mono_error_assert_ok (&error);
        if (!attrs) {
                mono_assemblies_lock ();
@@ -1824,9 +1898,27 @@ mono_assembly_load_friends (MonoAssembly* ass)
        mono_assemblies_unlock ();
 }
 
+struct HasReferenceAssemblyAttributeIterData {
+       gboolean has_attr;
+};
+
+static gboolean
+has_reference_assembly_attribute_iterator (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
+{
+       gboolean stop_scanning = FALSE;
+       struct HasReferenceAssemblyAttributeIterData *iter_data = (struct HasReferenceAssemblyAttributeIterData*)user_data;
+
+       if (!strcmp (name, "ReferenceAssemblyAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
+               /* Note we don't check the assembly name, same as coreCLR. */
+               iter_data->has_attr = TRUE;
+               stop_scanning = TRUE;
+       }
+
+       return stop_scanning;
+}
 
 /**
- * mono_assembly_get_reference_assembly_attribute:
+ * mono_assembly_has_reference_assembly_attribute:
  * @assembly: a MonoAssembly
  * @error: set on error.
  *
@@ -1834,25 +1926,20 @@ mono_assembly_load_friends (MonoAssembly* ass)
  * On error returns FALSE and sets @error.
  */
 gboolean
-mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
+mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
 
-       MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
-       return_val_if_nok (error, FALSE);
-       if (!attrs)
-               return FALSE;
-       MonoClass *ref_asm_class = mono_class_try_get_reference_assembly_class ();
-       gboolean result = FALSE;
-       for (int i = 0; i < attrs->num_attrs; ++i) {
-               MonoCustomAttrEntry *attr = &attrs->attrs [i];
-               if (attr->ctor && attr->ctor->klass && attr->ctor->klass == ref_asm_class) {
-                       result = TRUE;
-                       break;
-               }
-       }
-       mono_custom_attrs_free (attrs);
-       return result;
+       /*
+        * This might be called during assembly loading, so do everything using the low-level
+        * metadata APIs.
+        */
+
+       struct HasReferenceAssemblyAttributeIterData iter_data = { FALSE };
+
+       mono_assembly_metadata_foreach_custom_attr (assembly, &has_reference_assembly_attribute_iterator, &iter_data);
+
+       return iter_data.has_attr;
 }
 
 /**
@@ -1880,7 +1967,7 @@ mono_assembly_get_reference_assembly_attribute (MonoAssembly *assembly, MonoErro
 MonoAssembly *
 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
 {
-       return mono_assembly_open_full (filename, status, FALSE);
+       return mono_assembly_open_predicate (filename, FALSE, FALSE, NULL, NULL, status);
 }
 
 /**
@@ -1905,6 +1992,16 @@ mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
 MonoAssembly *
 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
                              MonoImageOpenStatus *status, gboolean refonly)
+{
+       return mono_assembly_load_from_predicate (image, fname, refonly, NULL, NULL, status);
+}
+
+MonoAssembly *
+mono_assembly_load_from_predicate (MonoImage *image, const char *fname,
+                                  gboolean refonly,
+                                  MonoAssemblyCandidatePredicate predicate,
+                                  gpointer user_data,
+                                  MonoImageOpenStatus *status)
 {
        MonoAssembly *ass, *ass2;
        char *base_dir;
@@ -1974,10 +2071,39 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
                }
        }
 
+       /* We need to check for ReferenceAssmeblyAttribute before we
+        * mark the assembly as loaded and before we fire the load
+        * hook. Otherwise mono_domain_fire_assembly_load () in
+        * appdomain.c will cache a mapping from the assembly name to
+        * this image and we won't be able to look for a different
+        * candidate. */
+
+       if (!refonly) {
+               MonoError refasm_error;
+               if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image for assembly '%s' (%s) has ReferenceAssemblyAttribute, skipping", ass->aname.name, image->name);
+                       g_free (ass);
+                       g_free (base_dir);
+                       mono_image_close (image);
+                       *status = MONO_IMAGE_IMAGE_INVALID;
+                       return NULL;
+               }
+               mono_error_cleanup (&refasm_error);
+       }
+
+       if (predicate && !predicate (ass, user_data)) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate returned FALSE, skipping '%s' (%s)\n", ass->aname.name, image->name);
+               g_free (ass);
+               g_free (base_dir);
+               mono_image_close (image);
+               *status = MONO_IMAGE_IMAGE_INVALID;
+               return NULL;
+       }
+
        mono_assemblies_lock ();
 
        if (image->assembly) {
-               /* 
+               /*
                 * This means another thread has already loaded the assembly, but not yet
                 * called the load hooks so the search hook can't find the assembly.
                 */
@@ -1990,6 +2116,8 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
                return ass2;
        }
 
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Prepared to set up assembly '%s' (%s)", ass->aname.name, image->name);
+
        image->assembly = ass;
 
        loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
@@ -2583,7 +2711,7 @@ probe_for_partial_name (const char *basepath, const char *fullname, MonoAssembly
        if (fullpath == NULL)
                return NULL;
        else {
-               MonoAssembly *res = mono_assembly_open (fullpath, status);
+               MonoAssembly *res = mono_assembly_open_predicate (fullpath, FALSE, FALSE, NULL, NULL, status);
                g_free (fullpath);
                return res;
        }
@@ -2665,27 +2793,21 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta
        res = probe_for_partial_name (gacpath, fullname, aname, status);
        g_free (gacpath);
 
+       g_free (fullname);
+       mono_assembly_name_free (aname);
+
        if (res)
                res->in_gac = TRUE;
        else {
                MonoDomain *domain = mono_domain_get ();
-               MonoReflectionAssembly *refasm;
 
-               refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE, &error);
+               res = mono_try_assembly_resolve (domain, name, NULL, FALSE, &error);
                if (!is_ok (&error)) {
-                       g_free (fullname);
-                       mono_assembly_name_free (aname);
                        mono_error_cleanup (&error);
                        if (*status == MONO_IMAGE_OK)
                                *status = MONO_IMAGE_IMAGE_INVALID;
                }
-
-               if (refasm)
-                       res = refasm->assembly;
        }
-       
-       g_free (fullname);
-       mono_assembly_name_free (aname);
 
        return res;
 }
@@ -2762,7 +2884,7 @@ mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
        if (strstr (aname->name, ".dll")) {
                len = strlen (aname->name) - 4;
                name = (gchar *)g_malloc (len + 1);
-               strncpy (name, aname->name, len);
+               memcpy (name, aname->name, len);
                name[len] = 0;
        } else
                name = g_strdup (aname->name);
@@ -2882,6 +3004,12 @@ assembly_binding_info_parsed (MonoAssemblyBindingInfo *info, void *user_data)
        if (!domain)
                return;
 
+       if (info->has_new_version && mono_assembly_is_problematic_version (info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision)) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Discarding assembly binding to problematic version %s v%d.%d.%d.%d",
+                       info->name, info->new_version.major, info->new_version.minor, info->new_version.build, info->new_version.revision);
+               return;
+       }
+
        for (tmp = domain->assembly_bindings; tmp; tmp = tmp->next) {
                info_tmp = (MonoAssemblyBindingInfo *)tmp->data;
                if (strcmp (info->name, info_tmp->name) == 0 && info_versions_equal (info, info_tmp))
@@ -3079,7 +3207,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImag
        if (strstr (aname->name, ".dll")) {
                len = strlen (filename) - 4;
                name = (gchar *)g_malloc (len + 1);
-               strncpy (name, aname->name, len);
+               memcpy (name, aname->name, len);
                name[len] = 0;
        } else {
                name = g_strdup (aname->name);
@@ -3106,7 +3234,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImag
                paths = extra_gac_paths;
                while (!result && *paths) {
                        fullpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", subpath, NULL);
-                       result = mono_assembly_open_full (fullpath, status, refonly);
+                       result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
                        g_free (fullpath);
                        paths++;
                }
@@ -3120,7 +3248,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImag
 
        fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (),
                        "mono", "gac", subpath, NULL);
-       result = mono_assembly_open_full (fullpath, status, refonly);
+       result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
        g_free (fullpath);
 
        if (result)
@@ -3169,7 +3297,7 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
 
        // This unusual directory layout can occur if mono is being built and run out of its own source repo
        if (assemblies_path) { // Custom assemblies path set via MONO_PATH or mono_set_assemblies_path
-               corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE);
+               corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE, NULL, NULL);
                if (corlib)
                        goto return_corlib_and_facades;
        }
@@ -3177,13 +3305,13 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
        /* Normal case: Load corlib from mono/<version> */
        corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
        if (assemblies_path) { // Custom assemblies path
-               corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
+               corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE, NULL, NULL);
                if (corlib) {
                        g_free (corlib_file);
                        goto return_corlib_and_facades;
                }
        }
-       corlib = load_in_path (corlib_file, default_path, status, FALSE);
+       corlib = load_in_path (corlib_file, default_path, status, FALSE, NULL, NULL);
        g_free (corlib_file);
 
 return_corlib_and_facades:
@@ -3193,6 +3321,57 @@ return_corlib_and_facades:
        return corlib;
 }
 
+static MonoAssembly*
+prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
+{
+       MonoError refasm_error;
+       error_init (&refasm_error);
+       if (candidate && !refonly && mono_assembly_has_reference_assembly_attribute (candidate, &refasm_error)) {
+               candidate = NULL;
+       }
+       mono_error_cleanup (&refasm_error);
+       return candidate;
+}
+
+gboolean
+mono_assembly_candidate_predicate_sn_same_name (MonoAssembly *candidate, gpointer ud)
+{
+       MonoAssemblyName *wanted_name = (MonoAssemblyName*)ud;
+       MonoAssemblyName *candidate_name = &candidate->aname;
+
+       g_assert (wanted_name != NULL);
+       g_assert (candidate_name != NULL);
+
+       if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY)) {
+               char * s = mono_stringify_assembly_name (wanted_name);
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted = %s\n", s);
+               g_free (s);
+               s = mono_stringify_assembly_name (candidate_name);
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate = %s\n", s);
+               g_free (s);
+       }
+
+       /* No wanted token, bail. */
+       if (0 == wanted_name->public_key_token [0]) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: wanted has no token, returning TRUE\n");
+               return TRUE;
+       }
+
+       if (0 == candidate_name->public_key_token [0]) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate has no token, returning FALSE\n");
+               return FALSE;
+       }
+
+
+       gboolean result = mono_assembly_names_equal (wanted_name, candidate_name);
+
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Predicate: candidate and wanted names %s\n",
+                   result ? "match, returning TRUE" : "don't match, returning FALSE");
+       return result;
+
+}
+
+
 MonoAssembly*
 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
                                                                  const char       *basedir, 
@@ -3208,7 +3387,7 @@ mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
        int len;
 
        aname = mono_assembly_remap_version (aname, &maped_aname);
-       
+
        /* Reflection only assemblies don't get assembly binding */
        if (!refonly)
                aname = mono_assembly_apply_binding (aname, &maped_name_pp);
@@ -3249,7 +3428,7 @@ mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
 
                if (basedir) {
                        fullpath = g_build_filename (basedir, filename, NULL);
-                       result = mono_assembly_open_full (fullpath, status, refonly);
+                       result = mono_assembly_open_predicate (fullpath, refonly, FALSE, NULL, NULL, status);
                        g_free (fullpath);
                        if (result) {
                                result->in_gac = FALSE;
@@ -3258,7 +3437,7 @@ mono_assembly_load_full_nosearch (MonoAssemblyName *aname,
                        }
                }
 
-               result = load_in_path (filename, default_path, status, refonly);
+               result = load_in_path (filename, default_path, status, refonly, NULL, NULL);
                if (result)
                        result->in_gac = FALSE;
                g_free (filename);
@@ -3274,9 +3453,11 @@ mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *request
 {
        MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
 
-       if (!result)
+       if (!result) {
                /* Try a postload search hook */
                result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
+               result = prevent_reference_assembly_from_running (result, refonly);
+       }
        return result;
 }