X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fassembly.c;h=69187a39eee43cdad5389575dbc8c619bc5fbbc7;hb=e152071d2a0061d7aa6d7f40b220b78f43132aa2;hp=b0ce1a5d921cd62360f2d50ef332e579b21079fc;hpb=44b4f6a73931d5000dab72ec6f26182ec7b7cfde;p=mono.git diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index b0ce1a5d921..69187a39eee 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -4,8 +4,8 @@ * Author: * Miguel de Icaza (miguel@ximian.com) * - * (C) 2001 Ximian, Inc. http://www.ximian.com - * + * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) */ #include #include @@ -15,7 +15,6 @@ #include #include "assembly.h" #include "image.h" -#include "rawbuffer.h" #include "object-internals.h" #include #include @@ -29,15 +28,21 @@ #include #include #include -#include +#include +#include #include +#include -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 #include #include #include #endif +#ifdef PLATFORM_MACOSX +#include +#endif + /* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */ typedef struct { const char* assembly_name; @@ -57,6 +62,7 @@ static char **assemblies_path = NULL; /* Contains the list of directories that point to auxiliary GACs */ static char **extra_gac_paths = NULL; +#ifndef DISABLE_ASSEMBLY_REMAPPING /* The list of system assemblies what will be remapped to the running * runtime version. WARNING: this list must be sorted. */ @@ -87,8 +93,12 @@ static const AssemblyVersionMap framework_assemblies [] = { {"Npgsql", 0}, {"PEAPI", 0}, {"System", 0}, + {"System.ComponentModel.DataAnnotations", 2}, + {"System.Configuration", 0}, {"System.Configuration.Install", 0}, + {"System.Core", 2}, {"System.Data", 0}, + {"System.Data.Linq", 2}, {"System.Data.OracleClient", 0}, {"System.Data.SqlXml", 0}, {"System.Design", 0}, @@ -103,12 +113,15 @@ static const AssemblyVersionMap framework_assemblies [] = { {"System.Security", 0}, {"System.ServiceProcess", 0}, {"System.Web", 0}, + {"System.Web.Abstractions", 2}, {"System.Web.Mobile", 0}, + {"System.Web.Routing", 2}, {"System.Web.Services", 0}, {"System.Windows.Forms", 0}, {"System.Xml", 0}, {"mscorlib", 0} }; +#endif /* * keeps track of loaded assemblies @@ -116,6 +129,27 @@ static const AssemblyVersionMap framework_assemblies [] = { static GList *loaded_assemblies = NULL; static MonoAssembly *corlib; +#if defined(__native_client__) + +/* On Native Client, allow mscorlib to be loaded from memory */ +/* instead of loaded off disk. If these are not set, default */ +/* mscorlib loading will take place */ + +/* NOTE: If mscorlib data is passed to mono in this way then */ +/* it needs to remain allocated during the use of mono. */ + +static void *corlibData = NULL; +static size_t corlibSize = 0; + +void +mono_set_corlib_data (void *data, size_t size) +{ + corlibData = data; + corlibSize = size; +} + +#endif + /* This protects loaded_assemblies and image->references */ #define mono_assemblies_lock() EnterCriticalSection (&assemblies_mutex) #define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex) @@ -129,6 +163,8 @@ static GSList *loaded_assembly_bindings = NULL; static MonoAssembly* mono_assembly_invoke_search_hook_internal (MonoAssemblyName *aname, gboolean refonly, gboolean postload); +static MonoBoolean +mono_assembly_is_in_gac (const gchar *filanem); static gchar* encode_public_tok (const guchar *token, gint32 len) @@ -146,6 +182,20 @@ encode_public_tok (const guchar *token, gint32 len) return res; } +/** + * mono_public_tokens_are_equal: + * @pubt1: first public key token + * @pubt2: second public key token + * + * Compare two public key tokens and return #TRUE is they are equal and #FALSE + * otherwise. + */ +gboolean +mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2) +{ + return memcmp (pubt1, pubt2, 16) == 0; +} + static void check_path_env (void) { @@ -170,6 +220,7 @@ check_path_env (void) if (g_getenv ("MONO_DEBUG") == NULL) return; + splitted = assemblies_path; while (*splitted) { if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR)) g_warning ("'%s' in MONO_PATH doesn't exist or has wrong permissions.", *splitted); @@ -203,7 +254,7 @@ check_extra_gac_path_env (void) { while (*splitted) { if (**splitted && !g_file_test (*splitted, G_FILE_TEST_IS_DIR)) - g_warning ("'%s' in MONO_GAC_PATH doesn't exist or has wrong permissions.", *splitted); + g_warning ("'%s' in MONO_GAC_PREFIX doesn't exist or has wrong permissions.", *splitted); splitted++; } @@ -212,19 +263,22 @@ 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)) + if (info->culture && aname->culture && strcmp (info->culture, aname->culture)) return FALSE; - if (strcmp ((const char *)info->public_key_token, (const char *)aname->public_key_token)) + if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token)) return FALSE; return TRUE; @@ -233,6 +287,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); } @@ -366,24 +423,12 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r) if (!l->public_key_token [0] || !r->public_key_token [0]) return TRUE; - if (strcmp ((char*)l->public_key_token, (char*)r->public_key_token)) + if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token)) return FALSE; return TRUE; } -static MonoAssembly* -search_loaded (MonoAssemblyName* aname, gboolean refonly) -{ - MonoAssembly *ass; - - ass = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE); - if (ass) - return ass; - - return NULL; -} - static MonoAssembly * load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status, MonoBoolean refonly) { @@ -475,12 +520,12 @@ mono_set_dirs (const char *assembly_dir, const char *config_dir) mono_set_config_dir (config_dir); } -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 static char * compute_base (char *path) { - char *p = rindex (path, '/'); + char *p = strrchr (path, '/'); if (p == NULL) return NULL; @@ -489,7 +534,7 @@ compute_base (char *path) return NULL; *p = 0; - p = rindex (path, '/'); + p = strrchr (path, '/'); if (p == NULL) return NULL; @@ -534,25 +579,7 @@ set_dirs (char *exe) g_free (mono); } -#endif /* PLATFORM_WIN32 */ - -#ifdef UNDER_CE -#undef GetModuleFileName -#define GetModuleFileName ceGetModuleFileNameA - -DWORD ceGetModuleFileNameA(HMODULE hModule, char* lpFilename, DWORD nSize) -{ - DWORD res = 0; - wchar_t* wbuff = (wchar_t*)LocalAlloc(LPTR, nSize*2); - res = GetModuleFileNameW(hModule, wbuff, nSize); - if (res) { - int len = wcslen(wbuff); - WideCharToMultiByte(CP_ACP, 0, wbuff, len, lpFilename, len, NULL, NULL); - } - LocalFree(wbuff); - return res; -} -#endif +#endif /* HOST_WIN32 */ /** * mono_set_rootdir: @@ -563,24 +590,59 @@ DWORD ceGetModuleFileNameA(HMODULE hModule, char* lpFilename, DWORD nSize) void mono_set_rootdir (void) { -#ifdef PLATFORM_WIN32 - gunichar2 moddir [MAXPATHLEN]; - gchar *bindir, *installdir, *root, *utf8name, *config; +#if defined(HOST_WIN32) || (defined(PLATFORM_MACOSX) && !defined(TARGET_ARM)) + gchar *bindir, *installdir, *root, *name, *resolvedname, *config; + +#ifdef HOST_WIN32 + name = mono_get_module_file_name ((HMODULE) &__ImageBase); +#else + { + /* + * _NSGetExecutablePath may return -1 to indicate buf is not large + * enough, but we ignore that case to avoid having to do extra dynamic + * allocation for the path and hope that 4096 is enough - this is + * ok in the Linux/Solaris case below at least... + */ + + gchar buf[4096]; + guint buf_size = sizeof (buf); + + if (_NSGetExecutablePath (buf, &buf_size) == 0) + name = g_strdup (buf); + + if (name == NULL) { + fallback (); + return; + } + + name = mono_path_resolve_symlinks (name); + } +#endif + + resolvedname = mono_path_resolve_symlinks (name); - GetModuleFileNameW (NULL, moddir, MAXPATHLEN); - utf8name = g_utf16_to_utf8 (moddir, -1, NULL, NULL, NULL); - bindir = g_path_get_dirname (utf8name); + bindir = g_path_get_dirname (resolvedname); installdir = g_path_get_dirname (bindir); root = g_build_path (G_DIR_SEPARATOR_S, installdir, "lib", NULL); config = g_build_filename (root, "..", "etc", NULL); +#ifdef HOST_WIN32 mono_set_dirs (root, config); +#else + if (g_file_test (root, G_FILE_TEST_EXISTS) && g_file_test (config, G_FILE_TEST_EXISTS)) + mono_set_dirs (root, config); + else + fallback (); +#endif g_free (config); g_free (root); g_free (installdir); g_free (bindir); - g_free (utf8name); + g_free (name); + g_free (resolvedname); +#elif defined(DISABLE_MONO_AUTODETECTION) + fallback (); #else char buf [4096]; int s; @@ -694,13 +756,15 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname) char* mono_stringify_assembly_name (MonoAssemblyName *aname) { + const char *quote = (aname->name && g_ascii_isspace (aname->name [0])) ? "\"" : ""; + return g_strdup_printf ( - "%s, Version=%d.%d.%d.%d, Culture=%s%s%s", - aname->name, + "%s%s%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s", + quote, aname->name, quote, aname->major, aname->minor, aname->build, aname->revision, aname->culture && *aname->culture? aname->culture: "neutral", - aname->public_key_token [0] ? ", PublicKeyToken=" : "", - aname->public_key_token [0] ? (char *)aname->public_key_token : ""); + aname->public_key_token [0] ? (char *)aname->public_key_token : "null", + (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : ""); } static gchar* @@ -735,6 +799,7 @@ mono_assembly_addref (MonoAssembly *assembly) InterlockedIncrement (&assembly->ref_count); } +#ifndef DISABLE_ASSEMBLY_REMAPPING static MonoAssemblyName * mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_aname) { @@ -783,6 +848,7 @@ mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_ana } return aname; } +#endif /* * mono_assembly_get_assemblyref: @@ -865,19 +931,21 @@ mono_assembly_load_reference (MonoImage *image, int index) reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status); if (reference == NULL){ - char *extra_msg = g_strdup (""); + char *extra_msg; if (status == MONO_IMAGE_ERROR_ERRNO && errno == ENOENT) { - extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly->basedir); + extra_msg = g_strdup_printf ("The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (%s).\n", image->assembly != NULL ? image->assembly->basedir : "" ); } else if (status == MONO_IMAGE_ERROR_ERRNO) { extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno)); } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) { extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n"); } else if (status == MONO_IMAGE_IMAGE_INVALID) { extra_msg = g_strdup ("The file exists but is not a valid assembly.\n"); + } else { + extra_msg = g_strdup (""); } - g_warning ("The following assembly referenced from %s could not be loaded:\n" + mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY, "The following assembly referenced from %s could not be loaded:\n" " Assembly: %s (assemblyref_index=%d)\n" " Version: %d.%d.%d.%d\n" " Public Key: %s\n%s", @@ -897,7 +965,7 @@ mono_assembly_load_reference (MonoImage *image, int index) if (reference != REFERENCE_MISSING){ mono_assembly_addref (reference); if (image->assembly) - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n", + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d", image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count); } else { if (image->assembly) @@ -1146,8 +1214,12 @@ absolute_dir (const gchar *filename) gchar *res; gint i; - if (g_path_is_absolute (filename)) - return g_path_get_dirname (filename); + if (g_path_is_absolute (filename)) { + part = g_path_get_dirname (filename); + res = g_strconcat (part, G_DIR_SEPARATOR_S, NULL); + g_free (part); + return res; + } cwd = g_get_current_dir (); mixed = g_build_filename (cwd, filename, NULL); @@ -1219,7 +1291,7 @@ mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *statu mono_assemblies_lock (); for (i = 0; !image && bundles [i]; ++i) { if (strcmp (bundles [i]->name, name) == 0) { - image = mono_image_open_from_data_full ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly); + image = mono_image_open_from_data_with_name ((char*)bundles [i]->data, bundles [i]->size, FALSE, status, refonly, name); break; } } @@ -1239,6 +1311,7 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo MonoAssembly *ass; MonoImageOpenStatus def_status; gchar *fname; + gchar *new_fname; g_return_val_if_fail (filename != NULL, NULL); @@ -1276,17 +1349,25 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo } mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, - "Assembly Loader probing location: '%s'.", filename); + "Assembly Loader probing location: '%s'.", fname); + + new_fname = NULL; + if (!mono_assembly_is_in_gac (fname)) + new_fname = mono_make_shadow_copy (fname); + if (new_fname && new_fname != fname) { + g_free (fname); + fname = new_fname; + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, + "Assembly Loader shadow-copied assembly to: '%s'.", fname); + } + image = NULL; if (bundles != NULL) image = mono_assembly_open_from_bundle (fname, status, refonly); - if (!image) { - mono_assemblies_lock (); + if (!image) image = mono_image_open_full (fname, status, refonly); - mono_assemblies_unlock (); - } if (!image){ if (*status == MONO_IMAGE_OK) @@ -1320,8 +1401,14 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo return ass; } +static void +free_item (gpointer val, gpointer user_data) +{ + g_free (val); +} + /* - * mono_load_friend_assemblies: + * mono_assembly_load_friends: * @ass: an assembly * * Load the list of friend assemblies that are allowed to access @@ -1331,14 +1418,39 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo * This is an internal method, we need this because when we load mscorlib * we do not have the mono_defaults.internals_visible_class loaded yet, * so we need to load these after we initialize the runtime. + * + * LOCKING: Acquires the assemblies lock plus the loader lock. */ void mono_assembly_load_friends (MonoAssembly* ass) { int i; - MonoCustomAttrInfo* attrs = mono_custom_attrs_from_assembly (ass); - if (!attrs) + MonoCustomAttrInfo* attrs; + GSList *list; + + if (ass->friend_assembly_names_inited) + return; + + attrs = mono_custom_attrs_from_assembly (ass); + if (!attrs) { + mono_assemblies_lock (); + ass->friend_assembly_names_inited = TRUE; + mono_assemblies_unlock (); return; + } + + mono_assemblies_lock (); + if (ass->friend_assembly_names_inited) { + mono_assemblies_unlock (); + return; + } + mono_assemblies_unlock (); + + list = NULL; + /* + * We build the list outside the assemblies lock, the worse that can happen + * is that we'll need to free the allocated list. + */ for (i = 0; i < attrs->num_attrs; ++i) { MonoCustomAttrEntry *attr = &attrs->attrs [i]; MonoAssemblyName *aname; @@ -1356,13 +1468,27 @@ mono_assembly_load_friends (MonoAssembly* ass) slen = 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)) { - ass->friend_assembly_names = g_slist_prepend (ass->friend_assembly_names, aname); + if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) { + list = g_slist_prepend (list, aname); } else { g_free (aname); } } mono_custom_attrs_free (attrs); + + mono_assemblies_lock (); + if (ass->friend_assembly_names_inited) { + mono_assemblies_unlock (); + g_slist_foreach (list, free_item, NULL); + g_slist_free (list); + return; + } + ass->friend_assembly_names = list; + + /* Because of the double checked locking pattern above */ + mono_memory_barrier (); + ass->friend_assembly_names_inited = TRUE; + mono_assemblies_unlock (); } /** @@ -1396,7 +1522,7 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, return NULL; } -#if defined (PLATFORM_WIN32) +#if defined (HOST_WIN32) { gchar *tmp_fn; int i; @@ -1426,20 +1552,27 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, mono_assembly_fill_assembly_name (image, &ass->aname); + if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) { + // MS.NET doesn't support loading other mscorlibs + g_free (ass); + g_free (base_dir); + mono_image_addref (mono_defaults.corlib); + *status = MONO_IMAGE_OK; + return mono_defaults.corlib->assembly; + } + /* Add a non-temporary reference because of ass->image */ mono_image_addref (image); - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s %p -> %s %p: %d\n", ass->aname.name, ass, image->name, image, image->ref_count); + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s %p -> %s %p: %d", ass->aname.name, ass, image->name, image, image->ref_count); /* - * Atomically search the loaded list and add ourselves to it if necessary. + * The load hooks might take locks so we can't call them while holding the + * assemblies lock. */ - mono_assemblies_lock (); if (ass->aname.name) { - /* avoid loading the same assembly twice for now... */ - ass2 = search_loaded (&ass->aname, refonly); + ass2 = mono_assembly_invoke_search_hook_internal (&ass->aname, refonly, FALSE); if (ass2) { - mono_assemblies_unlock (); g_free (ass); g_free (base_dir); mono_image_close (image); @@ -1448,14 +1581,32 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname, } } - g_assert (image->assembly == 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. + */ + mono_assemblies_unlock (); + ass2 = image->assembly; + g_free (ass); + g_free (base_dir); + mono_image_close (image); + *status = MONO_IMAGE_OK; + return ass2; + } + image->assembly = ass; loaded_assemblies = g_list_prepend (loaded_assemblies, ass); - if (mono_defaults.internals_visible_class) - mono_assembly_load_friends (ass); mono_assemblies_unlock (); +#ifdef HOST_WIN32 + if (image->is_module_handle) + mono_image_fixup_vtable (image); +#endif + mono_assembly_invoke_load_hook (ass); mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK); @@ -1540,6 +1691,10 @@ parse_public_key (const gchar *key, gchar** pubkey) bitlen = read32 (header + 12) >> 3; if ((bitlen + 16 + 4) != pkeylen) return FALSE; + + /* parsing is OK and the public key itself is not requested back */ + if (!pubkey) + return TRUE; /* Encode the size of the blob */ offset = 0; @@ -1556,14 +1711,14 @@ parse_public_key (const gchar *key, gchar** pubkey) arr [i] = g_ascii_xdigit_value (key [j++]) << 4; arr [i] |= g_ascii_xdigit_value (key [j++]); } - if (pubkey) - *pubkey = arr; + + *pubkey = arr; return TRUE; } static gboolean -build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, MonoAssemblyName *aname, gboolean save_public_key) +build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, MonoAssemblyName *aname, gboolean save_public_key) { gint major, minor, build, revision; gint len; @@ -1592,6 +1747,7 @@ build_assembly_name (const char *name, const char *version, const char *culture, aname->revision = 0; } + aname->flags = flags; aname->name = g_strdup (name); if (culture) { @@ -1602,17 +1758,20 @@ build_assembly_name (const char *name, const char *version, const char *culture, } if (token && strncmp (token, "null", 4) != 0) { + char *lower; + /* the constant includes the ending NULL, hence the -1 */ if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) { + mono_assembly_name_free (aname); return FALSE; } - char *lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH); + lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH); g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH); g_free (lower); } - if (key && strncmp (key, "null", 4) != 0) { - if (!parse_public_key (key, &pkey)) { + if (key) { + if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) { mono_assembly_name_free (aname); return FALSE; } @@ -1645,30 +1804,36 @@ parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemb return FALSE; } - res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, aname, FALSE); + res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, aname, FALSE); g_strfreev (parts); return res; } gboolean -mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined) +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 *version = NULL; gchar *culture = NULL; gchar *token = NULL; gchar *key = NULL; + gchar *retargetable = NULL; gboolean res; gchar *value; gchar **parts; gchar **tmp; gboolean version_defined; + gboolean token_defined; + guint32 flags = 0; if (!is_version_defined) is_version_defined = &version_defined; *is_version_defined = FALSE; + if (!is_token_defined) + is_token_defined = &token_defined; + *is_token_defined = FALSE; - parts = tmp = g_strsplit (name, ",", 4); + parts = tmp = g_strsplit (name, ",", 6); if (!tmp || !*tmp) { g_strfreev (tmp); return FALSE; @@ -1684,9 +1849,8 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole *is_version_defined = TRUE; version = g_strstrip (value + 8); if (strlen (version) == 0) { - return FALSE; + goto cleanup_and_fail; } - tmp++; continue; } @@ -1694,16 +1858,17 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole if (!g_ascii_strncasecmp (value, "Culture=", 8)) { culture = g_strstrip (value + 8); if (strlen (culture) == 0) { - return FALSE; + goto cleanup_and_fail; } tmp++; continue; } if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) { + *is_token_defined = TRUE; token = g_strstrip (value + 15); if (strlen (token) == 0) { - return FALSE; + goto cleanup_and_fail; } tmp++; continue; @@ -1712,7 +1877,21 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) { key = g_strstrip (value + 10); if (strlen (key) == 0) { - return FALSE; + goto cleanup_and_fail; + } + tmp++; + continue; + } + + if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) { + retargetable = g_strstrip (value + 13); + if (strlen (retargetable) == 0) { + goto cleanup_and_fail; + } + if (!g_ascii_strcasecmp (retargetable, "yes")) { + flags |= ASSEMBLYREF_RETARGETABLE_FLAG; + } else if (g_ascii_strcasecmp (retargetable, "no")) { + goto cleanup_and_fail; } tmp++; continue; @@ -1728,9 +1907,19 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole return FALSE; } - res = build_assembly_name (dllname, version, culture, token, key, aname, save_public_key); + /* if retargetable flag is set, then we must have a fully qualified name */ + if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) { + goto cleanup_and_fail; + } + + res = build_assembly_name (dllname, version, culture, token, key, flags, + aname, save_public_key); g_strfreev (parts); return res; + +cleanup_and_fail: + g_strfreev (parts); + return FALSE; } /** @@ -1746,7 +1935,58 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole gboolean mono_assembly_name_parse (const char *name, MonoAssemblyName *aname) { - return mono_assembly_name_parse_full (name, aname, FALSE, NULL); + return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL); +} + +/** + * mono_assembly_name_new: + * @name: name to parse + * + * Allocate a new MonoAssemblyName and fill its values from the + * passed @name. + * + * Returns: a newly allocated structure or NULL if there was any failure. + */ +MonoAssemblyName* +mono_assembly_name_new (const char *name) +{ + MonoAssemblyName *aname = g_new0 (MonoAssemblyName, 1); + if (mono_assembly_name_parse (name, aname)) + return aname; + g_free (aname); + return NULL; +} + +const char* +mono_assembly_name_get_name (MonoAssemblyName *aname) +{ + return aname->name; +} + +const char* +mono_assembly_name_get_culture (MonoAssemblyName *aname) +{ + return aname->culture; +} + +mono_byte* +mono_assembly_name_get_pubkeytoken (MonoAssemblyName *aname) +{ + if (aname->public_key_token [0]) + return aname->public_key_token; + return NULL; +} + +uint16_t +mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16_t *build, uint16_t *revision) +{ + if (minor) + *minor = aname->minor; + if (build) + *build = aname->build; + if (revision) + *revision = aname->revision; + return aname->major; } static MonoAssembly* @@ -1775,7 +2015,7 @@ probe_for_partial_name (const char *basepath, const char *fullname, MonoAssembly match = FALSE; if (match && strlen ((char*)aname->public_key_token) > 0 && - strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0) + !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token)) match = FALSE; if (match) { @@ -1824,7 +2064,10 @@ MonoAssembly* mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status) { MonoAssembly *res; - MonoAssemblyName *aname, base_name, maped_aname; + MonoAssemblyName *aname, base_name; +#ifndef DISABLE_ASSEMBLY_REMAPPING + MonoAssemblyName maped_aname; +#endif gchar *fullname, *gacpath; gchar **paths; @@ -1834,12 +2077,14 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta if (!mono_assembly_name_parse (name, aname)) return NULL; +#ifndef DISABLE_ASSEMBLY_REMAPPING /* * If no specific version has been requested, make sure we load the * correct version for system assemblies. */ if ((aname->major | aname->minor | aname->build | aname->revision) == 0) aname = mono_assembly_remap_version (aname, &maped_aname); +#endif res = mono_assembly_loaded (aname); if (res) { @@ -1892,6 +2137,67 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta return res; } +static MonoBoolean +mono_assembly_is_in_gac (const gchar *filename) +{ + const gchar *rootdir; + gchar *gp; + gchar **paths; + + if (filename == NULL) + return FALSE; + + for (paths = extra_gac_paths; paths && *paths; paths++) { + if (strstr (*paths, filename) != *paths) + continue; + + gp = (gchar *) (filename + strlen (*paths)); + if (*gp != G_DIR_SEPARATOR) + continue; + gp++; + if (strncmp (gp, "lib", 3)) + continue; + gp += 3; + if (*gp != G_DIR_SEPARATOR) + continue; + gp++; + if (strncmp (gp, "mono", 4)) + continue; + gp += 4; + if (*gp != G_DIR_SEPARATOR) + continue; + gp++; + if (strncmp (gp, "gac", 3)) + continue; + gp += 3; + if (*gp != G_DIR_SEPARATOR) + continue; + + return TRUE; + } + + rootdir = mono_assembly_getrootdir (); + if (strstr (filename, rootdir) != filename) + return FALSE; + + gp = (gchar *) (filename + strlen (rootdir)); + if (*gp != G_DIR_SEPARATOR) + return FALSE; + gp++; + if (strncmp (gp, "mono", 4)) + return FALSE; + gp += 4; + if (*gp != G_DIR_SEPARATOR) + return FALSE; + gp++; + if (strncmp (gp, "gac", 3)) + return FALSE; + gp += 3; + if (*gp != G_DIR_SEPARATOR) + return FALSE; + return TRUE; +} + static MonoImage* mono_assembly_load_publisher_policy (MonoAssemblyName *aname) { @@ -1907,10 +2213,9 @@ mono_assembly_load_publisher_policy (MonoAssemblyName *aname) } else name = g_strdup (aname->name); - if (aname->culture) { - culture = g_strdup (aname->culture); - g_strdown (culture); - } else + if (aname->culture) + culture = g_utf8_strdown (aname->culture, -1); + else culture = g_strdup (""); pname = g_strdup_printf ("policy.%d.%d.%s", aname->major, aname->minor, name); @@ -1977,17 +2282,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)) @@ -1997,14 +2420,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 */ @@ -2047,6 +2492,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag gchar *name, *version, *culture, *fullpath, *subpath; gint32 len; gchar **paths; + char *pubtok; if (aname->public_key_token [0] == 0) { return NULL; @@ -2061,15 +2507,16 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag } if (aname->culture) { - culture = g_strdup (aname->culture); - g_strdown (culture); + culture = g_utf8_strdown (aname->culture, -1); } else { culture = g_strdup (""); } + pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH); version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major, aname->minor, aname->build, aname->revision, - culture, aname->public_key_token); + culture, pubtok); + g_free (pubtok); subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL); g_free (name); @@ -2105,17 +2552,39 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag return result; } - MonoAssembly* mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *status) { char *corlib_file; + MonoAssemblyName *aname; if (corlib) { /* g_print ("corlib already loaded\n"); */ return corlib; } - + +#if defined(__native_client__) + if (corlibData != NULL && corlibSize != 0) { + int status = 0; + /* First "FALSE" instructs mono not to make a copy. */ + /* Second "FALSE" says this is not just a ref. */ + MonoImage* image = mono_image_open_from_data_full (corlibData, corlibSize, FALSE, &status, FALSE); + if (image == NULL || status != 0) + g_print("mono_image_open_from_data_full failed: %d\n", status); + corlib = mono_assembly_load_from_full (image, "mscorlib", &status, FALSE); + if (corlib == NULL || status != 0) + g_print ("mono_assembly_load_from_full failed: %d\n", status); + if (corlib) + return corlib; + } +#endif + + 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) { corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status, FALSE); if (corlib) @@ -2138,19 +2607,25 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus * return corlib; } -MonoAssembly* mono_assembly_load_full_nosearch (MonoAssemblyName *aname, - const char *basedir, - MonoImageOpenStatus *status, - gboolean refonly) +MonoAssembly* +mono_assembly_load_full_nosearch (MonoAssemblyName *aname, + const char *basedir, + MonoImageOpenStatus *status, + gboolean refonly) { MonoAssembly *result; char *fullpath, *filename; - MonoAssemblyName maped_aname, maped_name_pp; +#ifndef DISABLE_ASSEMBLY_REMAPPING + MonoAssemblyName maped_aname; +#endif + MonoAssemblyName maped_name_pp; int ext_index; const char *ext; int len; +#ifndef DISABLE_ASSEMBLY_REMAPPING aname = mono_assembly_remap_version (aname, &maped_aname); +#endif /* Reflection only assemblies don't get assembly binding */ if (!refonly) @@ -2261,13 +2736,13 @@ MonoAssembly* mono_assembly_loaded_full (MonoAssemblyName *aname, gboolean refonly) { MonoAssembly *res; +#ifndef DISABLE_ASSEMBLY_REMAPPING MonoAssemblyName maped_aname; aname = mono_assembly_remap_version (aname, &maped_aname); +#endif - mono_assemblies_lock (); - res = search_loaded (aname, refonly); - mono_assemblies_unlock (); + res = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE); return res; } @@ -2285,25 +2760,23 @@ mono_assembly_loaded (MonoAssemblyName *aname) return mono_assembly_loaded_full (aname, FALSE); } -/** - * mono_assembly_close: - * @assembly: the assembly to release. - * - * This method releases a reference to the @assembly. The assembly is - * only released when all the outstanding references to it are released. +/* + * Returns whether mono_assembly_close_finish() must be called as + * well. See comment for mono_image_close_except_pools() for why we + * unload in two steps. */ -void -mono_assembly_close (MonoAssembly *assembly) +gboolean +mono_assembly_close_except_image_pools (MonoAssembly *assembly) { GSList *tmp; - g_return_if_fail (assembly != NULL); + g_return_val_if_fail (assembly != NULL, FALSE); if (assembly == REFERENCE_MISSING) - return; - + return FALSE; + /* Might be 0 already */ if (InterlockedDecrement (&assembly->ref_count) > 0) - return; + return FALSE; mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD); @@ -2317,7 +2790,8 @@ mono_assembly_close (MonoAssembly *assembly) assembly->image->assembly = NULL; - mono_image_close (assembly->image); + if (!mono_image_close_except_pools (assembly->image)) + assembly->image = NULL; for (tmp = assembly->friend_assembly_names; tmp; tmp = tmp->next) { MonoAssemblyName *fname = tmp->data; @@ -2326,13 +2800,39 @@ mono_assembly_close (MonoAssembly *assembly) } g_slist_free (assembly->friend_assembly_names); g_free (assembly->basedir); + + mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD); + + return TRUE; +} + +void +mono_assembly_close_finish (MonoAssembly *assembly) +{ + g_assert (assembly && assembly != REFERENCE_MISSING); + + if (assembly->image) + mono_image_close_finish (assembly->image); + if (assembly->dynamic) { g_free ((char*)assembly->aname.culture); } else { g_free (assembly); } +} - mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD); +/** + * mono_assembly_close: + * @assembly: the assembly to release. + * + * This method releases a reference to the @assembly. The assembly is + * only released when all the outstanding references to it are released. + */ +void +mono_assembly_close (MonoAssembly *assembly) +{ + if (mono_assembly_close_except_image_pools (assembly)) + mono_assembly_close_finish (assembly); } MonoImage* @@ -2424,3 +2924,137 @@ mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies) { bundles = assemblies; } + +#define MONO_DECLSEC_FORMAT_10 0x3C +#define MONO_DECLSEC_FORMAT_20 0x2E +#define MONO_DECLSEC_FIELD 0x53 +#define MONO_DECLSEC_PROPERTY 0x54 + +#define SKIP_VISIBILITY_XML_ATTRIBUTE ("\"SkipVerification\"") +#define SKIP_VISIBILITY_ATTRIBUTE_NAME ("System.Security.Permissions.SecurityPermissionAttribute") +#define SKIP_VISIBILITY_ATTRIBUTE_SIZE (sizeof (SKIP_VISIBILITY_ATTRIBUTE_NAME) - 1) +#define SKIP_VISIBILITY_PROPERTY_NAME ("SkipVerification") +#define SKIP_VISIBILITY_PROPERTY_SIZE (sizeof (SKIP_VISIBILITY_PROPERTY_NAME) - 1) + +static gboolean +mono_assembly_try_decode_skip_verification_param (const char *p, const char **resp, gboolean *abort_decoding) +{ + int len; + switch (*p++) { + case MONO_DECLSEC_PROPERTY: + break; + case MONO_DECLSEC_FIELD: + default: + *abort_decoding = TRUE; + return FALSE; + break; + } + + if (*p++ != MONO_TYPE_BOOLEAN) { + *abort_decoding = TRUE; + return FALSE; + } + + /* property name length */ + len = mono_metadata_decode_value (p, &p); + + if (len >= SKIP_VISIBILITY_PROPERTY_SIZE && !memcmp (p, SKIP_VISIBILITY_PROPERTY_NAME, SKIP_VISIBILITY_PROPERTY_SIZE)) { + p += len; + return *p; + } + p += len + 1; + + *resp = p; + return FALSE; +} + +static gboolean +mono_assembly_try_decode_skip_verification (const char *p, const char *endn) +{ + int i, j, num, len, params_len; + + if (*p == MONO_DECLSEC_FORMAT_10) { + gsize read, written; + char *res = g_convert (p, endn - p, "UTF-8", "UTF-16LE", &read, &written, NULL); + if (res) { + gboolean found = strstr (res, SKIP_VISIBILITY_XML_ATTRIBUTE) != NULL; + g_free (res); + return found; + } + return FALSE; + } + if (*p++ != MONO_DECLSEC_FORMAT_20) + return FALSE; + + /* number of encoded permission attributes */ + num = mono_metadata_decode_value (p, &p); + for (i = 0; i < num; ++i) { + gboolean is_valid = FALSE; + gboolean abort_decoding = FALSE; + + /* attribute name length */ + len = mono_metadata_decode_value (p, &p); + + /* We don't really need to fully decode the type. Comparing the name is enough */ + is_valid = len >= SKIP_VISIBILITY_ATTRIBUTE_SIZE && !memcmp (p, SKIP_VISIBILITY_ATTRIBUTE_NAME, SKIP_VISIBILITY_ATTRIBUTE_SIZE); + + p += len; + + /*size of the params table*/ + params_len = mono_metadata_decode_value (p, &p); + if (is_valid) { + const char *params_end = p + params_len; + + /* number of parameters */ + len = mono_metadata_decode_value (p, &p); + + for (j = 0; j < len; ++j) { + if (mono_assembly_try_decode_skip_verification_param (p, &p, &abort_decoding)) + return TRUE; + if (abort_decoding) + break; + } + p = params_end; + } else { + p += params_len; + } + } + + return FALSE; +} + + +gboolean +mono_assembly_has_skip_verification (MonoAssembly *assembly) +{ + MonoTableInfo *t; + guint32 cols [MONO_DECL_SECURITY_SIZE]; + const char *blob; + int i, len; + + if (MONO_SECMAN_FLAG_INIT (assembly->skipverification)) + return MONO_SECMAN_FLAG_GET_VALUE (assembly->skipverification); + + t = &assembly->image->tables [MONO_TABLE_DECLSECURITY]; + + for (i = 0; i < t->rows; ++i) { + mono_metadata_decode_row (t, i, cols, MONO_DECL_SECURITY_SIZE); + if ((cols [MONO_DECL_SECURITY_PARENT] & MONO_HAS_DECL_SECURITY_MASK) != MONO_HAS_DECL_SECURITY_ASSEMBLY) + continue; + if (cols [MONO_DECL_SECURITY_ACTION] != SECURITY_ACTION_REQMIN) + continue; + + blob = mono_metadata_blob_heap (assembly->image, cols [MONO_DECL_SECURITY_PERMISSIONSET]); + len = mono_metadata_decode_blob_size (blob, &blob); + if (!len) + continue; + + if (mono_assembly_try_decode_skip_verification (blob, blob + len)) { + MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, TRUE); + return TRUE; + } + } + + MONO_SECMAN_FLAG_SET_VALUE (assembly->skipverification, FALSE); + return FALSE; +}