From 8db8db6695904acb792b6dcd6d93608b009c0134 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 18 Sep 2019 17:18:30 -0400 Subject: [PATCH] Make case-insensitive class lookup work correctly with exported types (mono/mono#16652) * Make case-insensitive class lookup work correctly with exported types * Search all matching namespaces * Skip AOT cache for case-insensitive lookups Commit migrated from https://github.com/mono/mono/commit/529a11cf5b7557851472d7cb646559e0d3b02763 --- src/mono/mono/metadata/class.c | 157 ++++++++++++++++++++----------------- src/mono/netcore/CoreFX.issues.rsp | 4 - 2 files changed, 83 insertions(+), 78 deletions(-) diff --git a/src/mono/mono/metadata/class.c b/src/mono/mono/metadata/class.c index 6bcf500..419e880 100644 --- a/src/mono/mono/metadata/class.c +++ b/src/mono/mono/metadata/class.c @@ -65,6 +65,9 @@ static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klas static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token); static guint32 mono_field_resolve_flags (MonoClassField *field); +static MonoClass * +mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, gboolean case_sensitive, MonoError *error); + GENERATE_GET_CLASS_WITH_CACHE (valuetype, "System", "ValueType") GENERATE_TRY_GET_CLASS_WITH_CACHE (handleref, "System.Runtime.InteropServices", "HandleRef") @@ -2943,6 +2946,20 @@ mono_image_add_to_name_cache (MonoImage *image, const char *nspace, typedef struct { gconstpointer key; + GSList *values; +} FindAllUserData; + +static void +find_all_nocase (gpointer key, gpointer value, gpointer user_data) +{ + char *name = (char*)key; + FindAllUserData *data = (FindAllUserData*)user_data; + if (mono_utf8_strcasecmp (name, (char*)data->key) == 0) + data->values = g_slist_prepend (data->values, value); +} + +typedef struct { + gconstpointer key; gpointer value; } FindUserData; @@ -2995,66 +3012,20 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char MonoClass * mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error) { - MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF]; - guint32 cols [MONO_TYPEDEF_SIZE]; - const char *n; - const char *nspace; - guint32 i, visib; - - error_init (error); - - if (image_is_dynamic (image)) { - guint32 token = 0; - FindUserData user_data; - - mono_image_init_name_cache (image); - mono_image_lock (image); - - user_data.key = name_space; - user_data.value = NULL; - g_hash_table_foreach (image->name_cache, find_nocase, &user_data); - - if (user_data.value) { - GHashTable *nspace_table = (GHashTable*)user_data.value; - - user_data.key = name; - user_data.value = NULL; + MonoClass *klass; + GHashTable *visited_images; - g_hash_table_foreach (nspace_table, find_nocase, &user_data); - - if (user_data.value) - token = GPOINTER_TO_UINT (user_data.value); - } + visited_images = g_hash_table_new (g_direct_hash, g_direct_equal); - mono_image_unlock (image); - - if (token) - return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error); - else - return NULL; + klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, FALSE, error); - } + g_hash_table_destroy (visited_images); - /* add a cache if needed */ - for (i = 1; i <= t->rows; ++i) { - mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE); - visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK; - /* - * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags - * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table - */ - if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) - continue; - n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); - nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0) - return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error); - } - return NULL; + return klass; } static MonoClass* -return_nested_in (MonoClass *klass, char *nested) +return_nested_in (MonoClass *klass, char *nested, gboolean case_sensitive) { MonoClass *found; char *s = strchr (nested, '/'); @@ -3066,9 +3037,16 @@ return_nested_in (MonoClass *klass, char *nested) } while ((found = mono_class_get_nested_types (klass, &iter))) { - if (strcmp (m_class_get_name (found), nested) == 0) { + const char *name = m_class_get_name (found); + gint strcmp_result; + if (case_sensitive) + strcmp_result = strcmp (name, nested); + else + strcmp_result = mono_utf8_strcasecmp (name, nested); + + if (strcmp_result == 0) { if (s) - return return_nested_in (found, s); + return return_nested_in (found, s, case_sensitive); return found; } } @@ -3076,7 +3054,7 @@ return_nested_in (MonoClass *klass, char *nested) } static MonoClass* -search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error) +search_modules (MonoImage *image, const char *name_space, const char *name, gboolean case_sensitive, MonoError *error) { MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE]; MonoImage *file_image; @@ -3099,7 +3077,11 @@ search_modules (MonoImage *image, const char *name_space, const char *name, Mono file_image = mono_image_load_file_for_image_checked (image, i + 1, error); if (file_image) { - klass = mono_class_from_name_checked (file_image, name_space, name, error); + if (case_sensitive) + klass = mono_class_from_name_checked (file_image, name_space, name, error); + else + klass = mono_class_from_name_case_checked (file_image, name_space, name, error); + if (klass || !is_ok (error)) return klass; } @@ -3109,10 +3091,10 @@ search_modules (MonoImage *image, const char *name_space, const char *name, Mono } static MonoClass * -mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error) +mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, gboolean case_sensitive, MonoError *error) { - GHashTable *nspace_table; - MonoImage *loaded_image; + GHashTable *nspace_table = NULL; + MonoImage *loaded_image = NULL; guint32 token = 0; int i; MonoClass *klass; @@ -3139,16 +3121,17 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons } /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */ - if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) { + // The AOT cache in get_class_from_name is case-sensitive, so don't bother with it for case-insensitive lookups + if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0 && case_sensitive) { gboolean res = get_class_from_name (image, name_space, name, &klass); if (res) { if (!klass) { - klass = search_modules (image, name_space, name, error); + klass = search_modules (image, name_space, name, case_sensitive, error); if (!is_ok (error)) return NULL; } if (nested) - return klass ? return_nested_in (klass, nested) : NULL; + return klass ? return_nested_in (klass, nested, case_sensitive) : NULL; else return klass; } @@ -3157,10 +3140,32 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons mono_image_init_name_cache (image); mono_image_lock (image); - nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space); + if (case_sensitive) { + nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space); + + if (nspace_table) + token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name)); + } else { + FindAllUserData all_user_data = { name_space, NULL }; + FindUserData user_data = { name, NULL }; + GSList *values; - if (nspace_table) - token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name)); + // We're forced to check all matching namespaces, not just the first one found, + // because our desired type could be in any of the ones that match case-insensitively. + g_hash_table_foreach (image->name_cache, find_all_nocase, &all_user_data); + + values = all_user_data.values; + while (values && !user_data.value) { + nspace_table = (GHashTable*)values->data; + g_hash_table_foreach (nspace_table, find_nocase, &user_data); + values = values->next; + } + + g_slist_free (all_user_data.values); + + if (user_data.value) + token = GPOINTER_TO_UINT (user_data.value); + } mono_image_unlock (image); @@ -3169,14 +3174,18 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons for (i = 0; i < image->module_count; ++i) { MonoImage *module = image->modules [i]; - klass = mono_class_from_name_checked (module, name_space, name, error); + if (case_sensitive) + klass = mono_class_from_name_checked (module, name_space, name, error); + else + klass = mono_class_from_name_case_checked (module, name_space, name, error); + if (klass || !is_ok (error)) return klass; } } if (!token) { - klass = search_modules (image, name_space, name, error); + klass = search_modules (image, name_space, name, case_sensitive, error); if (klass || !is_ok (error)) return klass; return NULL; @@ -3196,9 +3205,9 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error); if (!loaded_image) return NULL; - klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error); + klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, case_sensitive, error); if (nested) - return klass ? return_nested_in (klass, nested) : NULL; + return klass ? return_nested_in (klass, nested, case_sensitive) : NULL; return klass; } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) { guint32 assembly_idx; @@ -3209,9 +3218,9 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons g_assert (image->references [assembly_idx - 1]); if (image->references [assembly_idx - 1] == (gpointer)-1) return NULL; - klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error); + klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, case_sensitive, error); if (nested) - return klass ? return_nested_in (klass, nested) : NULL; + return klass ? return_nested_in (klass, nested, case_sensitive) : NULL; return klass; } else { g_assert_not_reached (); @@ -3222,7 +3231,7 @@ mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, cons klass = mono_class_get_checked (image, token, error); if (nested) - return return_nested_in (klass, nested); + return return_nested_in (klass, nested, case_sensitive); return klass; } @@ -3246,7 +3255,7 @@ mono_class_from_name_checked (MonoImage *image, const char* name_space, const ch visited_images = g_hash_table_new (g_direct_hash, g_direct_equal); - klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error); + klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, TRUE, error); g_hash_table_destroy (visited_images); diff --git a/src/mono/netcore/CoreFX.issues.rsp b/src/mono/netcore/CoreFX.issues.rsp index d18b0f4..1526907 100644 --- a/src/mono/netcore/CoreFX.issues.rsp +++ b/src/mono/netcore/CoreFX.issues.rsp @@ -555,10 +555,6 @@ # GC.GetGCMemoryInfo is not implemented -nomethod System.Tests.GCTests.GetGCMemoryInfo -# Could not load type 'System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' -# https://github.com/mono/mono/issues/15153 --nomethod System.Tests.ActivatorTests.TestingCreateInstanceObjectHandleFullSignature - # flaky test, System.ArgumentNullException : Key cannot be null. Parameter name: key -nomethod System.Tests.GetEnvironmentVariable.EnvironmentVariablesAreHashtable -- 2.7.4