Removed mono_debugger_create_notification_function() from here.
[mono.git] / mono / metadata / assembly.c
index 36d2e28d50ca07d6e1a3bd07d39b10b0b6b44e58..10dbacfd70d12d4a01c83c08c8e879f9d3f92331 100644 (file)
@@ -155,7 +155,7 @@ static void
 check_path_env (void)
 {
        const char *path;
-       char **splitted;
+       char **splitted, **dest;
        
        path = g_getenv ("MONO_PATH");
        if (!path)
@@ -164,7 +164,14 @@ check_path_env (void)
        splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
        if (assemblies_path)
                g_strfreev (assemblies_path);
-       assemblies_path = splitted;
+       assemblies_path = dest = splitted;
+       while (*splitted){
+               if (**splitted)
+                       *dest++ = *splitted;
+               splitted++;
+       }
+       *dest = *splitted;
+       
        if (g_getenv ("MONO_DEBUG") == NULL)
                return;
 
@@ -179,7 +186,7 @@ check_path_env (void)
 static void
 check_extra_gac_path_env (void) {
        const char *path;
-       char **splitted;
+       char **splitted, **dest;
        
        path = g_getenv ("MONO_GAC_PREFIX");
        if (!path)
@@ -188,7 +195,14 @@ check_extra_gac_path_env (void) {
        splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
        if (extra_gac_paths)
                g_strfreev (extra_gac_paths);
-       extra_gac_paths = splitted;
+       extra_gac_paths = dest = splitted;
+       while (*splitted){
+               if (**splitted)
+                       *dest++ = *splitted;
+               splitted++;
+       }
+       *dest = *splitted;
+       
        if (g_getenv ("MONO_DEBUG") == NULL)
                return;
 
@@ -331,6 +345,7 @@ check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
  * @r: second assembly.
  *
  * Compares two MonoAssemblyNames and returns whether they are equal.
+ *
  * This compares the names, the cultures, the release version and their
  * public tokens.
  *
@@ -356,7 +371,7 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
        if (!l->public_key_token [0] || !r->public_key_token [0])
                return TRUE;
 
-       if (strcmp (l->public_key_token, r->public_key_token))
+       if (strcmp ((char*)l->public_key_token, (char*)r->public_key_token))
                return FALSE;
 
        return TRUE;
@@ -377,7 +392,7 @@ search_loaded (MonoAssemblyName* aname, gboolean refonly)
         * The assembly might be under load by this thread. In this case, it is
         * safe to return an incomplete instance to prevent loops.
         */
-       loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, GetCurrentThread ());
+       loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, (gpointer)GetCurrentThreadId ());
        for (tmp = loading; tmp; tmp = tmp->next) {
                ass = tmp->data;
                if (!mono_assembly_names_equal (aname, &ass->aname))
@@ -411,8 +426,10 @@ load_in_path (const char *basename, const char** search_path, MonoImageOpenStatu
  * @root_dir: The pathname of the root directory where we will locate assemblies
  *
  * This routine sets the internal default root directory for looking up
- * assemblies.  This is used by Windows installations to compute dynamically
- * the place where the Mono assemblies are located.
+ * assemblies.
+ *
+ * This is used by Windows installations to compute dynamically the
+ * place where the Mono assemblies are located.
  *
  */
 void
@@ -427,8 +444,10 @@ mono_assembly_setrootdir (const char *root_dir)
 
 /**
  * mono_assembly_getrootdir:
+ * 
+ * Obtains the root directory used for looking up assemblies.
  *
- * Returns: The internal root directory used for looking up assemblies
+ * Returns: a string with the directory, this string should not be freed.
  */
 G_CONST_RETURN gchar *
 mono_assembly_getrootdir (void)
@@ -442,10 +461,11 @@ mono_assembly_getrootdir (void)
  * @config_dir: the base directory for configuration files
  *
  * This routine is used internally and by developers embedding
- * the runtime into their own applications.  There are a number
- * of cases to consider: Mono as a system-installed package that
- * is available on the location preconfigured or Mono in a relocated
- * location.
+ * the runtime into their own applications.
+ *
+ * There are a number of cases to consider: Mono as a system-installed
+ * package that is available on the location preconfigured or Mono in
+ * a relocated location.
  *
  * If you are using a system-installed Mono, you can pass NULL
  * to both parameters.  If you are not, you should compute both
@@ -632,20 +652,6 @@ mono_assemblies_init (void)
        assemblies_refonly_loading = g_hash_table_new (NULL, NULL);
 }
 
-/**
- * mono_assemblies_cleanup:
- *
- *  Free all resources used by this module.
- */
-void
-mono_assemblies_cleanup (void)
-{
-       DeleteCriticalSection (&assemblies_mutex);
-
-       g_hash_table_destroy (assemblies_loading);
-       g_hash_table_destroy (assemblies_refonly_loading);
-}
-
 gboolean
 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
 {
@@ -696,11 +702,15 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
        return TRUE;
 }
 
-/*
+/**
  * mono_stringify_assembly_name:
+ * @aname: the assembly name.
  *
- *   Convert @aname into its string format. The returned string is dynamically
+ * Convert @aname into its string format. The returned string is dynamically
  * allocated and should be freed by the caller.
+ *
+ * Returns: a newly allocated string with a string representation of
+ * the assembly name.
  */
 char*
 mono_stringify_assembly_name (MonoAssemblyName *aname)
@@ -861,7 +871,7 @@ mono_assembly_load_reference (MonoImage *image, int index)
                 * a non loaded reference using the ReflectionOnly api
                */
                if (!reference)
-                       reference = (gpointer)-1;
+                       reference = REFERENCE_MISSING;
        } else
                reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
 
@@ -891,12 +901,19 @@ mono_assembly_load_reference (MonoImage *image, int index)
        mono_assemblies_lock ();
        if (reference == NULL) {
                /* Flag as not found */
-               reference = (gpointer)-1;
+               reference = REFERENCE_MISSING;
        }       
 
        if (!image->references [index]) {
-               mono_assembly_addref (reference);
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n", image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
+               if (reference != REFERENCE_MISSING){
+                       mono_assembly_addref (reference);
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n",
+                                   image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
+               } else {
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
+                                   image->assembly->aname.name, image->assembly);
+               }
+               
                image->references [index] = reference;
        }
        mono_assemblies_unlock ();
@@ -961,6 +978,17 @@ mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
        assembly_load_hook = hook;
 }
 
+static void
+free_assembly_load_hooks (void)
+{
+       AssemblyLoadHook *hook, *next;
+
+       for (hook = assembly_load_hook; hook; hook = next) {
+               next = hook->next;
+               g_free (hook);
+       }
+}
+
 typedef struct AssemblySearchHook AssemblySearchHook;
 struct AssemblySearchHook {
        AssemblySearchHook *next;
@@ -1016,6 +1044,17 @@ mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_da
        mono_install_assembly_search_hook_internal (func, user_data, FALSE, FALSE);
 }      
 
+static void
+free_assembly_search_hooks (void)
+{
+       AssemblySearchHook *hook, *next;
+
+       for (hook = assembly_search_hook; hook; hook = next) {
+               next = hook->next;
+               g_free (hook);
+       }
+}
+
 void
 mono_install_assembly_refonly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
 {
@@ -1102,6 +1141,22 @@ mono_install_assembly_refonly_preload_hook (MonoAssemblyPreLoadFunc func, gpoint
        assembly_refonly_preload_hook = hook;
 }
 
+static void
+free_assembly_preload_hooks (void)
+{
+       AssemblyPreLoadHook *hook, *next;
+
+       for (hook = assembly_preload_hook; hook; hook = next) {
+               next = hook->next;
+               g_free (hook);
+       }
+
+       for (hook = assembly_refonly_preload_hook; hook; hook = next) {
+               next = hook->next;
+               g_free (hook);
+       }
+}
+
 static gchar *
 absolute_dir (const gchar *filename)
 {
@@ -1140,11 +1195,12 @@ absolute_dir (const gchar *filename)
        list = g_list_reverse (list);
 
        /* Ignores last data pointer, which should be the filename */
-       for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
+       for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
                if (tmp->data)
                        g_string_append_printf (result, "%s%c", (char *) tmp->data,
                                                                G_DIR_SEPARATOR);
-       
+       }
+
        res = result->str;
        g_string_free (result, FALSE);
        g_list_free (list);
@@ -1245,12 +1301,13 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo
 
        if (!image) {
                mono_assemblies_lock ();
-               image = mono_image_open_full (filename, status, refonly);
+               image = mono_image_open_full (fname, status, refonly);
                mono_assemblies_unlock ();
        }
 
        if (!image){
-               *status = MONO_IMAGE_ERROR_ERRNO;
+               if (*status == MONO_IMAGE_OK)
+                       *status = MONO_IMAGE_ERROR_ERRNO;
                g_free (fname);
                return NULL;
        }
@@ -1329,8 +1386,9 @@ load_friend_assemblies (MonoAssembly* ass)
  * mono_assembly_open opens the PE-image pointed by @filename, and
  * loads any external assemblies referenced by it.
  *
- * NOTE: we could do lazy loading of the assemblies.  Or maybe not worth
- * it. 
+ * Return: a pointer to the MonoAssembly if @filename contains a valid
+ * assembly or NULL on error.  Details about the error are stored in the
+ * @status variable.
  */
 MonoAssembly *
 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
@@ -1340,13 +1398,20 @@ mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
 
 MonoAssembly *
 mono_assembly_load_from_full (MonoImage *image, const char*fname, 
-                        MonoImageOpenStatus *status, gboolean refonly)
+                             MonoImageOpenStatus *status, gboolean refonly)
 {
        MonoAssembly *ass, *ass2;
        char *base_dir;
        GList *loading;
        GHashTable *ass_loading;
 
+       if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
+               /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
+               *status = MONO_IMAGE_IMAGE_INVALID;
+               return NULL;
+       }
+
+
 #if defined (PLATFORM_WIN32)
        {
                gchar *tmp_fn;
@@ -1405,9 +1470,9 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
                }
        }
        ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading;
-       loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
+       loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ());
        loading = g_list_prepend (loading, ass);
-       g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
+       g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading);
        mono_assemblies_unlock ();
 
        g_assert (image->assembly == NULL);
@@ -1417,13 +1482,13 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
 
        mono_assemblies_lock ();
 
-       loading = g_hash_table_lookup (ass_loading, GetCurrentThread ());
+       loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ());
        loading = g_list_remove (loading, ass);
        if (loading == NULL)
                /* Prevent memory leaks */
-               g_hash_table_remove (ass_loading, GetCurrentThread ());
+               g_hash_table_remove (ass_loading, (gpointer)GetCurrentThreadId ());
        else
-               g_hash_table_insert (ass_loading, GetCurrentThread (), loading);
+               g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading);
        if (*status != MONO_IMAGE_OK) {
                mono_assemblies_unlock ();
                mono_assembly_close (ass);
@@ -1458,12 +1523,12 @@ mono_assembly_load_from (MonoImage *image, const char *fname,
 }
 
 /**
-* mono_assembly_name_free:
-* @aname: assembly name to free
-* 
-* Frees the provided assembly name object.
-* (it does not frees the object itself, only the name members).
-*/
+ * mono_assembly_name_free:
+ * @aname: assembly name to free
+ 
+ * Frees the provided assembly name object.
+ * (it does not frees the object itself, only the name members).
+ */
 void
 mono_assembly_name_free (MonoAssemblyName *aname)
 {
@@ -1554,18 +1619,29 @@ build_assembly_name (const char *name, const char *version, const char *culture,
 {
        gint major, minor, build, revision;
        gint len;
+       gint version_parts;
        gchar *pkey, *pkeyptr, *encoded, tok [8];
 
        memset (aname, 0, sizeof (MonoAssemblyName));
 
        if (version) {
-               if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
+               version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
+               if (version_parts < 2 || version_parts > 4)
                        return FALSE;
 
+               /* FIXME: we should set build & revision to -1 (instead of 0)
+               if these are not set in the version string. That way, later on,
+               we can still determine if these were specified. */
                aname->major = major;
                aname->minor = minor;
-               aname->build = build;
-               aname->revision = revision;
+               if (version_parts >= 3)
+                       aname->build = build;
+               else
+                       aname->build = 0;
+               if (version_parts == 4)
+                       aname->revision = revision;
+               else
+                       aname->revision = 0;
        }
        
        aname->name = g_strdup (name);
@@ -1687,14 +1763,15 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole
 }
 
 /**
-* mono_assembly_name_parse:
-* @name: name to parse
-* @aname: the destination assembly name
-* Returns: true if the name could be parsed.
-* 
-* Parses an assembly qualified type name and assigns the name,
-* version, culture and token to the provided assembly name object.
-*/
+ * mono_assembly_name_parse:
+ * @name: name to parse
+ * @aname: the destination assembly name
+ * 
+ * Parses an assembly qualified type name and assigns the name,
+ * version, culture and token to the provided assembly name object.
+ *
+ * Returns: true if the name could be parsed.
+ */
 gboolean
 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
 {
@@ -2083,7 +2160,22 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
        return corlib;
 }
 
-
+/**
+ * mono_assembly_load_full:
+ * @aname: A MonoAssemblyName with the assembly name to load.
+ * @basedir: A directory to look up the assembly at.
+ * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
+ * @refonly: Whether this assembly is being opened in "reflection-only" mode.
+ *
+ * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
+ * attempts to load the assembly from that directory before probing the standard locations.
+ *
+ * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
+ * assembly binding takes place.
+ *
+ * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
+ * value pointed by status is updated with an error code.
+ */
 MonoAssembly*
 mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
 {
@@ -2092,6 +2184,7 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage
        MonoAssemblyName maped_aname, maped_name_pp;
        int ext_index;
        const char *ext;
+       int len;
 
        aname = mono_assembly_remap_version (aname, &maped_aname);
        
@@ -2116,12 +2209,16 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage
                return mono_assembly_load_corlib (mono_get_runtime_info (), status);
        }
 
+       len = strlen (aname->name);
        for (ext_index = 0; ext_index < 2; ext_index ++) {
                ext = ext_index == 0 ? ".dll" : ".exe";
-               if (strstr (aname->name, ".dll"))
+               if (len > 4 && (!strcmp (aname->name + len - 4, ".dll") || !strcmp (aname->name + len - 4, ".exe"))) {
                        filename = g_strdup (aname->name);
-               else
+                       /* Don't try appending .dll/.exe if it already has one of those extensions */
+                       ext_index++;
+               } else {
                        filename = g_strconcat (aname->name, ext, NULL);
+               }
 
                result = mono_assembly_load_from_gac (aname, filename, status, refonly);
                if (result) {
@@ -2154,6 +2251,18 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage
        return result;
 }
 
+/**
+ * mono_assembly_load:
+ * @aname: A MonoAssemblyName with the assembly name to load.
+ * @basedir: A directory to look up the assembly at.
+ * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
+ *
+ * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
+ * attempts to load the assembly from that directory before probing the standard locations.
+ *
+ * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
+ * value pointed by status is updated with an error code.
+ */
 MonoAssembly*
 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
 {
@@ -2175,6 +2284,13 @@ mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
        return res;
 }
 
+/**
+ * mono_assembly_loaded:
+ * @aname: an assembly to look for.
+ *
+ * Returns: NULL If the given @aname assembly has not been loaded, or a pointer to
+ * a MonoAssembly that matches the MonoAssemblyName specified.
+ */
 MonoAssembly*
 mono_assembly_loaded (MonoAssemblyName *aname)
 {
@@ -2194,6 +2310,9 @@ mono_assembly_close (MonoAssembly *assembly)
        GSList *tmp;
        g_return_if_fail (assembly != NULL);
 
+       if (assembly == REFERENCE_MISSING)
+               return;
+       
        /* Might be 0 already */
        if (InterlockedDecrement (&assembly->ref_count) > 0)
                return;
@@ -2211,6 +2330,9 @@ mono_assembly_close (MonoAssembly *assembly)
                        if (assembly->image->references [i])
                                mono_assembly_close (assembly->image->references [i]);
                }
+
+               g_free (assembly->image->references);
+               assembly->image->references = NULL;
        }
 
        assembly->image->assembly = NULL;
@@ -2225,7 +2347,7 @@ mono_assembly_close (MonoAssembly *assembly)
        g_slist_free (assembly->friend_assembly_names);
        g_free (assembly->basedir);
        if (assembly->dynamic) {
-               g_free (assembly->aname.culture);
+               g_free ((char*)assembly->aname.culture);
        } else {
                g_free (assembly);
        }
@@ -2262,6 +2384,34 @@ mono_assembly_foreach (GFunc func, gpointer user_data)
        g_list_free (copy);
 }
 
+/**
+ * mono_assemblies_cleanup:
+ *
+ * Free all resources used by this module.
+ */
+void
+mono_assemblies_cleanup (void)
+{
+       GSList *l;
+
+       DeleteCriticalSection (&assemblies_mutex);
+
+       g_hash_table_destroy (assemblies_loading);
+       g_hash_table_destroy (assemblies_refonly_loading);
+
+       for (l = loaded_assembly_bindings; l; l = l->next) {
+               MonoAssemblyBindingInfo *info = l->data;
+
+               mono_assembly_binding_info_free (info);
+               g_free (info);
+       }
+       g_slist_free (loaded_assembly_bindings);
+
+       free_assembly_load_hooks ();
+       free_assembly_search_hooks ();
+       free_assembly_preload_hooks ();
+}
+
 /*
  * Holds the assembly of the application, for
  * System.Diagnostics.Process::MainModule
@@ -2271,16 +2421,25 @@ static MonoAssembly *main_assembly=NULL;
 void
 mono_assembly_set_main (MonoAssembly *assembly)
 {
-       main_assembly=assembly;
+       main_assembly = assembly;
 }
 
+/**
+ * mono_assembly_get_main:
+ *
+ * Returns: the assembly for the application, the first assembly that is loaded by the VM
+ */
 MonoAssembly *
 mono_assembly_get_main (void)
 {
-       return(main_assembly);
+       return (main_assembly);
 }
 
-/*
+/**
+ * mono_assembly_get_image:
+ * @assembly: The assembly to retrieve the image from
+ *
+ * Returns: the MonoImage associated with this assembly.
  */
 MonoImage*
 mono_assembly_get_image (MonoAssembly *assembly)