From f513229d29bd8234cd25faa59abee39f0a59c75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Tue, 30 Mar 2021 13:14:03 -0400 Subject: [PATCH] [mbr] Fix encmap boundary and method RVA lookup. (#50254) Two separate issues: 1. When we process the EnC map, any tables after the last one that has an update gets an "enc_recs" pointer that's one past the last row of the table. (the enc_recs pointer is used to speed up relative address lookup). So at lookup time if enc_recs says to look past the end of the EnC map table, we know there won't be any updates - return -1. 2. When looking for the updated RVA of a method, we need to go through every delta and find the latest one that has an update for the given method. The problem is that if a later generation doesn't have an update, we would take the NULL return value at face value and it would look like the method had no updates to its body - we would go back to using the original version from before any updates were applied. Instead now ignore lookup table misses and remember the last successful lookup. Fixes https://github.com/dotnet/runtime/issues/50190 --- src/mono/mono/metadata/loader.c | 14 ++++++++++++-- src/mono/mono/metadata/metadata-update.c | 10 +++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index 1b473b075f610..1fda9a1dd3824 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -2000,6 +2000,7 @@ get_method_update_rva (MonoImage *image_base, uint32_t idx) { gpointer loc = NULL; uint32_t cur = mono_metadata_update_get_thread_generation (); + int generation = -1; GList *ptr = image_base->delta_image; /* Go through all the updates that the current thread can see and see * if they updated the method. Keep the latest visible update */ @@ -2007,9 +2008,18 @@ get_method_update_rva (MonoImage *image_base, uint32_t idx) MonoImage *image_delta = (MonoImage*) ptr->data; if (image_delta->generation > cur) break; - if (image_delta->method_table_update) - loc = g_hash_table_lookup (image_delta->method_table_update, GUINT_TO_POINTER (idx)); + if (image_delta->method_table_update) { + gpointer result = g_hash_table_lookup (image_delta->method_table_update, GUINT_TO_POINTER (idx)); + /* if it's not in the table of a later generation, the + * later generation didn't modify the method + */ + if (result != NULL) { + loc = result; + generation = image_delta->generation; + } + } } + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_METADATA_UPDATE, "method lookup idx=0x%08x returned gen=%d il=%p", idx, generation, loc); return loc; } #endif diff --git a/src/mono/mono/metadata/metadata-update.c b/src/mono/mono/metadata/metadata-update.c index 2bcb6cf1518fd..0b2aaf9c287d0 100644 --- a/src/mono/mono/metadata/metadata-update.c +++ b/src/mono/mono/metadata/metadata-update.c @@ -635,11 +635,18 @@ mono_image_relative_delta_index (MonoImage *image_dmeta, int token) g_assert (delta_info); int index_map = delta_info->enc_recs [table]; + int encmap_rows = encmap->rows; + + /* if the table didn't have any updates in this generation and the + * table index is bigger than the last table that got updates, + * enc_recs will point past the last row */ + if (index_map - 1 == encmap_rows) + return -1; guint32 cols[MONO_ENCMAP_SIZE]; mono_metadata_decode_row (encmap, index_map - 1, cols, MONO_ENCMAP_SIZE); int map_entry = cols [MONO_ENCMAP_TOKEN]; - while (mono_metadata_token_table (map_entry) == table && mono_metadata_token_index (map_entry) < index && index_map < encmap->rows) { + while (mono_metadata_token_table (map_entry) == table && mono_metadata_token_index (map_entry) < index && index_map < encmap_rows) { mono_metadata_decode_row (encmap, ++index_map - 1, cols, MONO_ENCMAP_SIZE); map_entry = cols [MONO_ENCMAP_TOKEN]; } @@ -847,6 +854,7 @@ apply_enclog_pass1 (MonoImage *image_base, MonoImage *image_dmeta, gconstpointer static void set_update_method (MonoImage *image_base, uint32_t generation, MonoImage *image_dmeta, uint32_t token_index, const char* il_address) { + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_METADATA_UPDATE, "setting method 0x%08x in g=%d IL=%p", token_index, generation, (void*)il_address); /* FIXME: this is a race if other threads are doing a lookup. */ g_hash_table_insert (image_base->method_table_update, GUINT_TO_POINTER (token_index), GUINT_TO_POINTER (generation)); g_hash_table_insert (image_dmeta->method_table_update, GUINT_TO_POINTER (token_index), (gpointer) il_address);