Skip to content

Commit

Permalink
[Mono] Race in init_method when using LLVM AOT. (dotnet#75088)
Browse files Browse the repository at this point in the history
[Mono] Race in init_method when using LLVM AOT.

When using LLVM AOT codegen, init_method updates two GOT slots. 
These slots are initialized as part of init_method, but there is a race between
initialization of the two slots. Current implementation can have two threads
running init_method for the same method, but as soon as:

[got_slots [pindex]] = addr

store is visible, it will trigger other threads to return back from init_method,
but since that could happen before the corresponding LLVM AOT const slot is set,
second thread will return to method calling init_method, load the LLVM aot const,
and crash when trying to use it (since its still NULL).

This crash is very rare but have been identified on x86/x64 CPU's, when one thread
is either preempted between updating regular GOT slot and LLVM GOT slot or store
into LLVM GOT slot gets delayed in store buffer. I have also been able to emulate the
scenario in debugger, triggering the issue and crashing in the method loading from
LLVM aot const slot.

Fix change order of updates and make sure the update of LLVM aot const slot happens
before memory_barrier, since:

got [got_slots [pindex]] = addr;

have release semantics in relation to addr and update of LLVM aot const slot. Fix also add
acquire/release semantics for ji->type in init_method since it is used to guard if a thread
ignores a patch or not and it should not be re-ordered with previous stores, since it can
cause similar race conditions with updated slots.
  • Loading branch information
lateralusX authored Sep 9, 2022
1 parent 11c8988 commit f591e98
Showing 1 changed file with 14 additions and 10 deletions.
24 changes: 14 additions & 10 deletions src/mono/mono/mini/aot-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -4628,10 +4628,13 @@ init_method (MonoAotModule *amodule, gpointer info, guint32 method_index, MonoMe
* been initialized by load_method () for a static cctor before the cctor has
* finished executing (#23242).
*/
if (ji->type == MONO_PATCH_INFO_NONE) {
} else if (!got [got_slots [pindex]] || ji->type == MONO_PATCH_INFO_SFLDA) {
MonoJumpInfoType ji_type = ji->type;
LOAD_ACQUIRE_FENCE;

if (ji_type == MONO_PATCH_INFO_NONE) {
} else if (!got [got_slots [pindex]] || ji_type == MONO_PATCH_INFO_SFLDA) {
/* In llvm-only made, we might encounter shared methods */
if (mono_llvm_only && ji->type == MONO_PATCH_INFO_METHOD && mono_method_check_context_used (ji->data.method)) {
if (mono_llvm_only && ji_type == MONO_PATCH_INFO_METHOD && mono_method_check_context_used (ji->data.method)) {
g_assert (context);
ji->data.method = mono_class_inflate_generic_method_checked (ji->data.method, context, error);
if (!is_ok (error)) {
Expand All @@ -4641,10 +4644,10 @@ init_method (MonoAotModule *amodule, gpointer info, guint32 method_index, MonoMe
}
}
/* This cannot be resolved in mono_resolve_patch_target () */
if (ji->type == MONO_PATCH_INFO_AOT_JIT_INFO) {
if (ji_type == MONO_PATCH_INFO_AOT_JIT_INFO) {
// FIXME: Lookup using the index
jinfo = mono_aot_find_jit_info (amodule->assembly->image, code);
ji->type = MONO_PATCH_INFO_ABS;
ji->type = ji_type = MONO_PATCH_INFO_ABS;
ji->data.target = jinfo;
}
addr = mono_resolve_patch_target (method, code, ji, TRUE, error);
Expand All @@ -4653,18 +4656,19 @@ init_method (MonoAotModule *amodule, gpointer info, guint32 method_index, MonoMe
mono_mempool_destroy (mp);
return FALSE;
}
if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
if (ji_type == MONO_PATCH_INFO_METHOD_JUMP) {
addr = mono_create_ftnptr (addr);
mono_memory_barrier ();
got [got_slots [pindex]] = addr;
if (ji->type == MONO_PATCH_INFO_METHOD_JUMP)
register_jump_target_got_slot (ji->data.method, &(got [got_slots [pindex]]));

}
if (llvm) {
void (*init_aotconst) (int, gpointer) = (void (*)(int, gpointer))amodule->info.llvm_init_aotconst;
init_aotconst (got_slots [pindex], addr);
}
mono_memory_barrier ();
got [got_slots [pindex]] = addr;
}

STORE_RELEASE_FENCE;
ji->type = MONO_PATCH_INFO_NONE;
}

Expand Down

0 comments on commit f591e98

Please sign in to comment.