Skip to content

Commit 9af92a9

Browse files
authored
[mono][interp] Fix race when registering patch point data items (#119990)
The code of a compiled method can use data items that contain InterpMethod* pointers. Because at the moment when a method is compiled these referenced interp methods weren't yet tiered up, we will register these data item locations to the tiering backend so that, when they do get tiered up, the locations get updated with the new InterpMethod* reference. At this moment of compilation time, we could race with other compilers of the same InterpMethod so we could end up registering redundant data_items (only the data_items for the method winning the race will actually end up being used by the executing interpreter code). Normally this is harmless, we just patch some data that never gets used. The problems start when we free interpreter methods. When the interp method is freed, we need to clear the patch_sites_table of any locations pointing into this method's data items. We do a search starting from the data items of this method. Because we have no way to reference the wrongly registered data items, these entries will stay alive in the table. As the memory gets reused, these entries will point into other runtime code, and when the get patched, it will result in corruption of memory. We fix this issue by registering the patch sites only for the method winning the compilation race (the one that first sets the transformed flag).
1 parent fc1dee6 commit 9af92a9

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

src/mono/mono/mini/interp/transform.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9666,7 +9666,7 @@ get_native_offset (TransformData *td, int il_offset, gboolean precise)
96669666
return GPTRDIFF_TO_INT (td->new_code_end - td->new_code);
96679667
}
96689668

9669-
static void
9669+
static GSList*
96709670
generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoGenericContext *generic_context, MonoError *error)
96719671
{
96729672
TransformData transform_data;
@@ -9863,7 +9863,6 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG
98639863
memcpy (rtm->data_items, td->data_items, td->n_data_items * sizeof (td->data_items [0]));
98649864
rtm->n_data_items = td->n_data_items;
98659865

9866-
mono_interp_register_imethod_data_items (rtm->data_items, td->imethod_items);
98679866
rtm->patchpoint_data = td->patchpoint_data;
98689867

98699868
if (td->ref_slots) {
@@ -9937,7 +9936,6 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG
99379936
g_ptr_array_free (td->seq_points, TRUE);
99389937
if (td->line_numbers)
99399938
g_array_free (td->line_numbers, TRUE);
9940-
g_slist_free (td->imethod_items);
99419939
for (GSList *l = td->headers_to_free; l; l = l->next)
99429940
mono_metadata_free_mh ((MonoMethodHeader *)l->data);
99439941
mono_mempool_destroy (td->mempool);
@@ -9947,6 +9945,8 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG
99479945
retry_with_inlining = td->retry_with_inlining;
99489946
goto retry;
99499947
}
9948+
9949+
return td->imethod_items;
99509950
}
99519951

99529952
gboolean
@@ -10096,7 +10096,8 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Mon
1009610096
memcpy (&tmp_imethod, imethod, sizeof (InterpMethod));
1009710097
imethod = &tmp_imethod;
1009810098

10099-
MONO_TIME_TRACK (mono_interp_stats.transform_time, generate (method, header, imethod, generic_context, error));
10099+
GSList *imethod_data_items;
10100+
MONO_TIME_TRACK (mono_interp_stats.transform_time, imethod_data_items = generate (method, header, imethod, generic_context, error));
1010010101

1010110102
mono_metadata_free_mh (header);
1010210103

@@ -10117,6 +10118,8 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Mon
1011710118
mono_interp_stats.methods_transformed++;
1011810119
mono_atomic_fetch_add_i32 (&mono_jit_stats.methods_with_interp, 1);
1011910120

10121+
mono_interp_register_imethod_data_items (imethod->data_items, imethod_data_items);
10122+
1012010123
// FIXME Publishing of seq points seems to be racy with tiereing. We can have both tiered and untiered method
1012110124
// running at the same time. We could therefore get the optimized imethod seq points for the unoptimized method.
1012210125
gpointer seq_points = dn_simdhash_ght_get_value_or_default (jit_mm->seq_points, imethod->method);
@@ -10125,6 +10128,8 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Mon
1012510128
}
1012610129
jit_mm_unlock (jit_mm);
1012710130

10131+
g_slist_free (imethod_data_items);
10132+
1012810133
if (mono_stats_method_desc && mono_method_desc_full_match (mono_stats_method_desc, imethod->method)) {
1012910134
g_printf ("Printing runtime stats at method: %s\n", mono_method_get_full_name (imethod->method));
1013010135
mono_runtime_print_stats ();

0 commit comments

Comments
 (0)