#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>
#include <mono/utils/mono-digest.h>
#include <mono/utils/mono-logger-internal.h>
#include <mono/utils/mono-path.h>
* 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.
+ *
+ * .NET version can be found at https://github.com/dotnet/coreclr/blob/master/src/inc/fxretarget.h#L99
+ *
*/
static const AssemblyVersionMap framework_assemblies [] = {
{"Accessibility", 0},
{"I18N.Other", 0},
{"I18N.Rare", 0},
{"I18N.West", 0},
+ {"Microsoft.Build.Engine", 2},
+ {"Microsoft.Build.Framework", 2},
{"Microsoft.VisualBasic", 1},
{"Microsoft.VisualC", 1},
{"Mono.Cairo", 0},
{"Npgsql", 0},
{"PEAPI", 0},
{"System", 0},
+ {"System.ComponentModel.Composition", 2},
{"System.ComponentModel.DataAnnotations", 2},
{"System.Configuration", 0},
{"System.Configuration.Install", 0},
{"System.Drawing", 0},
{"System.Drawing.Design", 0},
{"System.EnterpriseServices", 0},
+ {"System.IdentityModel", 3},
+ {"System.IdentityModel.Selectors", 3},
{"System.Management", 0},
{"System.Messaging", 0},
{"System.Net", 2},
{"System.Runtime.Serialization", 3},
{"System.Runtime.Serialization.Formatters.Soap", 0},
{"System.Security", 0},
+ {"System.ServiceModel", 3},
{"System.ServiceModel.Web", 2},
{"System.ServiceProcess", 0},
{"System.Transactions", 0},
#endif
+static char* unquote (const char *str);
+
/* This protects loaded_assemblies and image->references */
-#define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex)
-#define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
-static CRITICAL_SECTION assemblies_mutex;
+#define mono_assemblies_lock() mono_mutex_lock (&assemblies_mutex)
+#define mono_assemblies_unlock() mono_mutex_unlock (&assemblies_mutex)
+static mono_mutex_t assemblies_mutex;
/* If defined, points to the bundled assembly information */
const MonoBundledAssembly **bundles;
static GSList *loaded_assembly_bindings = NULL;
static MonoAssembly*
-mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload);
+mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload);
+static MonoAssembly*
+mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly);
static MonoBoolean
mono_assembly_is_in_gac (const gchar *filanem);
void
mono_set_dirs (const char *assembly_dir, const char *config_dir)
{
-#if defined (MONO_ASSEMBLIES)
if (assembly_dir == NULL)
- assembly_dir = MONO_ASSEMBLIES;
-#endif
-#if defined (MONO_CFG_DIR)
+ assembly_dir = mono_config_get_assemblies_dir ();
if (config_dir == NULL)
- config_dir = MONO_CFG_DIR;
-#endif
+ config_dir = mono_config_get_cfg_dir ();
mono_assembly_setrootdir (assembly_dir);
mono_set_config_dir (config_dir);
}
return NULL;
/* Not a well known Mono executable, we are embedded, cant guess the base */
- if (strcmp (p, "/mono") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis") && strcmp (p, "/mint") && strcmp (p, "/monodiet"))
+ if (strcmp (p, "/mono") && strcmp (p, "/mono-boehm") && strcmp (p, "/mono-sgen") && strcmp (p, "/pedump") && strcmp (p, "/monodis"))
return NULL;
*p = 0;
static void
fallback (void)
{
- mono_set_dirs (MONO_ASSEMBLIES, MONO_CFG_DIR);
+ mono_set_dirs (mono_config_get_assemblies_dir (), mono_config_get_cfg_dir ());
}
static G_GNUC_UNUSED void
char *base;
char *config, *lib, *mono;
struct stat buf;
+ const char *bindir;
/*
* Only /usr prefix is treated specially
*/
- if (strncmp (exe, MONO_BINDIR, strlen (MONO_BINDIR)) == 0 || (base = compute_base (exe)) == NULL){
+ bindir = mono_config_get_bin_dir ();
+ g_assert (bindir);
+ if (strncmp (exe, bindir, strlen (bindir)) == 0 || (base = compute_base (exe)) == NULL){
fallback ();
return;
}
check_path_env ();
check_extra_gac_path_env ();
- InitializeCriticalSection (&assemblies_mutex);
+ mono_mutex_init_recursive (&assemblies_mutex);
mono_mutex_init (&assembly_binding_mutex);
}
if (image->assembly && image->assembly->ref_only) {
/* We use the loaded corlib */
if (!strcmp (aname.name, "mscorlib"))
- reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
+ reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
else {
reference = mono_assembly_loaded_full (&aname, TRUE);
if (!reference)
/* Try a postload search hook */
- reference = mono_assembly_invoke_search_hook_internal (&aname, TRUE, TRUE);
+ reference = mono_assembly_invoke_search_hook_internal (&aname, image->assembly, TRUE, TRUE);
}
/*
* The second load attempt has the basedir set to keep compatibility with the old mono behavior, for
* example bug-349190.2.cs and who knows how much more code in the wild.
*/
- reference = mono_assembly_load (&aname, NULL, &status);
+ reference = mono_assembly_load_full_internal (&aname, image->assembly, NULL, &status, FALSE);
if (!reference && image->assembly)
- reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
+ reference = mono_assembly_load_full_internal (&aname, image->assembly, image->assembly->basedir, &status, FALSE);
}
if (reference == NULL){
AssemblySearchHook *assembly_search_hook = NULL;
static MonoAssembly*
-mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload)
+mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, MonoAssembly *requesting, gboolean refonly, gboolean postload)
{
AssemblySearchHook *hook;
for (hook = assembly_search_hook; hook; hook = hook->next) {
if ((hook->refonly == refonly) && (hook->postload == postload)) {
- MonoAssembly *ass = hook->func (aname, hook->user_data);
+ MonoAssembly *ass;
+ /**
+ * A little explanation is in order here.
+ *
+ * The default postload search hook needs to know the requesting assembly to report it to managed code.
+ * The embedding API exposes a search hook that doesn't take such argument.
+ *
+ * The original fix would call the default search hook before all the registered ones and pass
+ * the requesting assembly to it. It works but broke a very suddle embedding API aspect that some users
+ * rely on. Which is the ordering between user hooks and the default runtime hook.
+ *
+ * Registering the hook after mono_jit_init would let your hook run before the default one and
+ * when using it to handle non standard app layouts this could save your app from a massive amount
+ * of syscalls that the default hook does when probing all sorts of places. Slow targets with horrible IO
+ * are all using this trick and if we broke this assumption they would be very disapointed at us.
+ *
+ * So what's the fix? We register the default hook using regular means and special case it when iterating
+ * over the registered hooks. This preserves ordering and enables managed resolve hooks to get the requesting
+ * assembly.
+ */
+ if (hook->func == (void*)mono_domain_assembly_postload_search)
+ ass = mono_domain_assembly_postload_search (aname, requesting, refonly);
+ else
+ ass = hook->func (aname, hook->user_data);
if (ass)
return ass;
}
MonoAssembly*
mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
{
- return mono_assembly_invoke_search_hook_internal (aname, FALSE, FALSE);
+ return mono_assembly_invoke_search_hook_internal (aname, NULL, FALSE, FALSE);
}
static void
image = NULL;
+ // If VM built with mkbundle
loaded_from_bundle = FALSE;
if (bundles != NULL) {
image = mono_assembly_open_from_bundle (fname, status, refonly);
MonoCustomAttrEntry *attr = &attrs->attrs [i];
MonoAssemblyName *aname;
const gchar *data;
- guint slen;
/* Do some sanity checking */
if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
continue;
/* 0xFF means null string, see custom attr format */
if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
continue;
- slen = mono_metadata_decode_value (data + 2, &data);
+ mono_metadata_decode_value (data + 2, &data);
aname = g_new0 (MonoAssemblyName, 1);
/*g_print ("friend ass: %s\n", data);*/
if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
* assemblies lock.
*/
if (ass->aname.name) {
- ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, refonly, FALSE);
+ ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, NULL, refonly, FALSE);
if (ass2) {
g_free (ass);
g_free (base_dir);
mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
{
gchar *dllname;
+ gchar *dllname_uq;
gchar *version = NULL;
+ gchar *version_uq;
gchar *culture = NULL;
+ gchar *culture_uq;
gchar *token = NULL;
+ gchar *token_uq;
gchar *key = NULL;
+ gchar *key_uq;
gchar *retargetable = NULL;
+ gchar *retargetable_uq;
+ gchar *procarch;
+ gchar *procarch_uq;
gboolean res;
gchar *value, *part_name;
guint32 part_name_len;
if (part_name_len == 12 && !g_ascii_strncasecmp (part_name, "Retargetable", part_name_len)) {
retargetable = value;
- if (strlen (retargetable) == 0) {
- goto cleanup_and_fail;
- }
+ retargetable_uq = unquote (retargetable);
+ if (retargetable_uq != NULL)
+ retargetable = retargetable_uq;
+
if (!g_ascii_strcasecmp (retargetable, "yes")) {
flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
} else if (g_ascii_strcasecmp (retargetable, "no")) {
+ free (retargetable_uq);
goto cleanup_and_fail;
}
+
+ free (retargetable_uq);
tmp++;
continue;
}
if (part_name_len == 21 && !g_ascii_strncasecmp (part_name, "ProcessorArchitecture", part_name_len)) {
- if (!g_ascii_strcasecmp (value, "MSIL"))
+ procarch = value;
+ procarch_uq = unquote (procarch);
+ if (procarch_uq != NULL)
+ procarch = procarch_uq;
+
+ if (!g_ascii_strcasecmp (procarch, "MSIL"))
arch = MONO_PROCESSOR_ARCHITECTURE_MSIL;
- else if (!g_ascii_strcasecmp (value, "X86"))
+ else if (!g_ascii_strcasecmp (procarch, "X86"))
arch = MONO_PROCESSOR_ARCHITECTURE_X86;
- else if (!g_ascii_strcasecmp (value, "IA64"))
+ else if (!g_ascii_strcasecmp (procarch, "IA64"))
arch = MONO_PROCESSOR_ARCHITECTURE_IA64;
- else if (!g_ascii_strcasecmp (value, "AMD64"))
+ else if (!g_ascii_strcasecmp (procarch, "AMD64"))
arch = MONO_PROCESSOR_ARCHITECTURE_AMD64;
- else
+ else {
+ free (procarch_uq);
goto cleanup_and_fail;
+ }
+
+ free (procarch_uq);
tmp++;
continue;
}
goto cleanup_and_fail;
}
- res = build_assembly_name (dllname, version, culture, token, key, flags, arch,
- aname, save_public_key);
+ dllname_uq = unquote (dllname);
+ version_uq = unquote (version);
+ culture_uq = unquote (culture);
+ token_uq = unquote (token);
+ key_uq = unquote (key);
+
+ res = build_assembly_name (
+ dllname_uq == NULL ? dllname : dllname_uq,
+ version_uq == NULL ? version : version_uq,
+ culture_uq == NULL ? culture : culture_uq,
+ token_uq == NULL ? token : token_uq,
+ 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_strfreev (parts);
return res;
return FALSE;
}
+static char*
+unquote (const char *str)
+{
+ gint slen;
+ const char *end;
+
+ if (str == NULL)
+ return NULL;
+
+ slen = strlen (str);
+ if (slen < 2)
+ return NULL;
+
+ if (*str != '\'' && *str != '\"')
+ return NULL;
+
+ end = str + slen - 1;
+ if (*str != *end)
+ return NULL;
+
+ return g_strndup (str + 1, slen - 2);
+}
+
/**
* mono_assembly_name_parse:
* @name: name to parse
res->in_gac = TRUE;
else {
MonoDomain *domain = mono_domain_get ();
- MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE);
+ MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), NULL, FALSE);
if (refasm)
res = refasm->assembly;
}
return corlib;
}
+ // In native client, Corlib is embedded in the executable as static variable corlibData
#if defined(__native_client__)
if (corlibData != NULL && corlibSize != 0) {
int status = 0;
}
#endif
+ // A nonstandard preload hook may provide a special mscorlib assembly
aname = mono_assembly_name_new ("mscorlib.dll");
corlib = invoke_assembly_preload_hook (aname, assemblies_path);
mono_assembly_name_free (aname);
if (corlib != NULL)
return corlib;
- if (assemblies_path) {
+ // 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);
if (corlib)
return corlib;
}
- /* Load corlib from mono/<version> */
-
+ /* Normal case: Load corlib from mono/<version> */
corlib_file = g_build_filename ("mono", runtime->framework_version, "mscorlib.dll", NULL);
- if (assemblies_path) {
+ if (assemblies_path) { // Custom assemblies path
corlib = load_in_path (corlib_file, (const char**)assemblies_path, status, FALSE);
if (corlib) {
g_free (corlib_file);
return result;
}
+MonoAssembly*
+mono_assembly_load_full_internal (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
+{
+ MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
+
+ if (!result)
+ /* Try a postload search hook */
+ result = mono_assembly_invoke_search_hook_internal (aname, requesting, refonly, TRUE);
+ return result;
+}
+
/**
* mono_assembly_load_full:
* @aname: A MonoAssemblyName with the assembly name to load.
MonoAssembly*
mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
{
- MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
-
- if (!result)
- /* Try a postload search hook */
- result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
- return result;
+ return mono_assembly_load_full_internal (aname, NULL, basedir, status, refonly);
}
/**
MonoAssembly*
mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
{
- return mono_assembly_load_full (aname, basedir, status, FALSE);
+ return mono_assembly_load_full_internal (aname, NULL, basedir, status, FALSE);
}
-
+
MonoAssembly*
mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly)
{
aname = mono_assembly_remap_version (aname, &maped_aname);
- res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
+ res = mono_assembly_invoke_search_hook_internal (aname, NULL, refonly, FALSE);
return res;
}
if (assembly == NULL || assembly == REFERENCE_MISSING)
return;
- if (assembly->dynamic) {
+ if (assembly_is_dynamic (assembly)) {
int i;
MonoDynamicImage *dynimg = (MonoDynamicImage *)assembly->image;
for (i = 0; i < dynimg->image.module_count; ++i)
if (assembly->image)
mono_image_close_finish (assembly->image);
- if (assembly->dynamic) {
+ if (assembly_is_dynamic (assembly)) {
g_free ((char*)assembly->aname.culture);
} else {
g_free (assembly);
{
GSList *l;
- DeleteCriticalSection (&assemblies_mutex);
+ mono_mutex_destroy (&assemblies_mutex);
mono_mutex_destroy (&assembly_binding_mutex);
for (l = loaded_assembly_bindings; l; l = l->next) {
return assembly->image;
}
+/**
+ * mono_assembly_get_name:
+ * @assembly: The assembly to retrieve the name from
+ *
+ * The returned name's lifetime is the same as @assembly's.
+ *
+ * Returns: the MonoAssemblyName associated with this assembly.
+ */
+MonoAssemblyName *
+mono_assembly_get_name (MonoAssembly *assembly)
+{
+ return &assembly->aname;
+}
+
void
mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
{