Merge pull request #3802 from lambdageek/dev-reference-attr-take3
[mono.git] / mono / metadata / assembly.c
index 0744389c400bf4539c0d88f3e530df2a95436b6e..9efcf1db486445dec64ee79c733593dbd7511391 100644 (file)
@@ -16,7 +16,9 @@
 #include <string.h>
 #include <stdlib.h>
 #include "assembly.h"
+#include "assembly-internals.h"
 #include "image.h"
+#include "image-internals.h"
 #include "object-internals.h"
 #include <mono/metadata/loader.h>
 #include <mono/metadata/tabledefs.h>
@@ -212,6 +214,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)
 {
@@ -557,6 +562,21 @@ mono_assembly_getrootdir (void)
        return default_path [0];
 }
 
+/**
+ * mono_native_getrootdir:
+ * 
+ * Obtains the root directory used for looking up native libs (.so, .dylib).
+ *
+ * Returns: a string with the directory, this string should be freed by
+ * the caller.
+ */
+gchar *
+mono_native_getrootdir (void)
+{
+       gchar* fullpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), mono_config_get_reloc_lib_dir(), NULL);
+       return fullpath;
+}
+
 /**
  * mono_set_dirs:
  * @assembly_dir: the base directory for assemblies
@@ -1192,22 +1212,6 @@ mono_assembly_load_reference (MonoImage *image, int index)
                                   strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
                g_free (extra_msg);
 
-       } else if (!image->assembly->ref_only) {
-               MonoError error;
-               if (mono_assembly_get_reference_assembly_attribute (reference, &error)) {
-                       mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following reference assembly assembly referenced from %s was not loaded.  Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context:\n"
-                                   "     Assembly:   %s    (assemblyref_index=%d)\n"
-                                   "     Version:    %d.%d.%d.%d\n"
-                                   "     Public Key: %s\n",
-                                   image->name, aname.name, index,
-                                   aname.major, aname.minor, aname.build, aname.revision,
-                                   strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token);
-                       reference = NULL; /* don't load reference assemblies for execution */
-               }
-               if (!is_ok (&error)) {
-                       reference = NULL;
-                       mono_error_cleanup (&error);
-               }
        }
 
        mono_assemblies_lock ();
@@ -1562,8 +1566,9 @@ mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *statu
 {
        int i;
        char *name;
+       gchar *lowercase_filename;
        MonoImage *image = NULL;
-
+       gboolean is_satellite = FALSE;
        /*
         * we do a very simple search for bundled assemblies: it's not a general 
         * purpose assembly loading mechanism.
@@ -1572,11 +1577,13 @@ mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *statu
        if (!bundles)
                return NULL;
 
+       lowercase_filename = g_utf8_strdown (filename, -1);
+       is_satellite = g_str_has_suffix (lowercase_filename, ".resources.dll");
+       g_free (lowercase_filename);
        name = g_path_get_basename (filename);
-
        mono_assemblies_lock ();
        for (i = 0; !image && bundles [i]; ++i) {
-               if (strcmp (bundles [i]->name, name) == 0) {
+               if (strcmp (bundles [i]->name, is_satellite ? filename : name) == 0) {
                        image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name);
                        break;
                }
@@ -1584,7 +1591,7 @@ mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *statu
        mono_assemblies_unlock ();
        if (image) {
                mono_image_addref (image);
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", name);
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", is_satellite ? filename : name);
                g_free (name);
                return image;
        }
@@ -1761,7 +1768,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 ();
@@ -1823,7 +1830,7 @@ mono_assembly_load_friends (MonoAssembly* ass)
 
 
 /**
- * mono_assembly_get_reference_assembly_attribute:
+ * mono_assembly_has_reference_assembly_attribute:
  * @assembly: a MonoAssembly
  * @error: set on error.
  *
@@ -1831,25 +1838,28 @@ 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);
 
-       MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, error);
+/* TODO: mono_custom_attrs_from_assembly_checked returns NULL if a
+ * single assembly is missing.  The custom attr we want is from
+ * corlib, however, so we need a more robust version that doesn't care
+ * about missing attributes.
+ */
+#if 1
+       MonoCustomAttrInfo *attrs = mono_custom_attrs_from_assembly_checked (assembly, TRUE, 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;
-               }
-       }
+       g_assert (ref_asm_class != NULL && ref_asm_class != mono_defaults.object_class && !strcmp(ref_asm_class->name, "ReferenceAssemblyAttribute") );
+       gboolean result = mono_custom_attrs_has_attr (attrs, ref_asm_class);
        mono_custom_attrs_free (attrs);
        return result;
+#else
+       return FALSE;
+#endif
 }
 
 /**
@@ -1987,8 +1997,38 @@ 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;
 
+       /* 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 && strcmp (ass->aname.name, "mscorlib") != 0) {
+               /* Don't check for reference assmebly attribute for
+                * corlib here because if corlib isn't loaded yet,
+                * it's too early to set up the
+                * ReferenceAssemblyAttribute class.  We check that
+                * we're not running with a reference corlib in
+                * mono_init_internal().
+                */
+               MonoError refasm_error;
+               if (mono_assembly_has_reference_assembly_attribute (ass, &refasm_error)) {
+                       mono_assemblies_unlock ();
+                       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);
+       }
+
        loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
        mono_assemblies_unlock ();
 
@@ -2355,11 +2395,11 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole
                        if (!g_ascii_strcasecmp (retargetable, "yes")) {
                                flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
                        } else if (g_ascii_strcasecmp (retargetable, "no")) {
-                               free (retargetable_uq);
+                               g_free (retargetable_uq);
                                goto cleanup_and_fail;
                        }
 
-                       free (retargetable_uq);
+                       g_free (retargetable_uq);
                        tmp++;
                        continue;
                }
@@ -2379,11 +2419,11 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole
                        else if (!g_ascii_strcasecmp (procarch, "AMD64"))
                                arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
                        else {
-                               free (procarch_uq);
+                               g_free (procarch_uq);
                                goto cleanup_and_fail;
                        }
 
-                       free (procarch_uq);
+                       g_free (procarch_uq);
                        tmp++;
                        continue;
                }
@@ -2411,11 +2451,11 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole
                key_uq == NULL ? key : key_uq,
                flags, arch, aname, save_public_key);
 
-       free (dllname_uq);
-       free (version_uq);
-       free (culture_uq);
-       free (token_uq);
-       free (key_uq);
+       g_free (dllname_uq);
+       g_free (version_uq);
+       g_free (culture_uq);
+       g_free (token_uq);
+       g_free (key_uq);
 
        g_strfreev (parts);
        return res;
@@ -3190,6 +3230,19 @@ return_corlib_and_facades:
        return corlib;
 }
 
+static MonoAssembly*
+prevent_reference_assembly_from_running (MonoAssembly* candidate, gboolean refonly)
+{
+       MonoError refasm_error;
+       mono_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;
+}
+
+
 MonoAssembly*
 mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
                                                                  const char       *basedir, 
@@ -3271,9 +3324,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;
 }
 
@@ -3447,9 +3502,19 @@ mono_assembly_close (MonoAssembly *assembly)
 MonoImage*
 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
 {
-       return mono_image_load_file_for_image (assembly->image, idx);
+       MonoError error;
+       MonoImage *result = mono_assembly_load_module_checked (assembly, idx, &error);
+       mono_error_assert_ok (&error);
+       return result;
+}
+
+MONO_API MonoImage*
+mono_assembly_load_module_checked (MonoAssembly *assembly, uint32_t idx, MonoError *error)
+{
+       return mono_image_load_file_for_image_checked (assembly->image, idx, error);
 }
 
+
 /**
  * mono_assembly_foreach:
  * @func: function to invoke for each assembly loaded