Skip to content

Commit

Permalink
Pass the default ALC gchandle to the v3 preload hook (#54686)
Browse files Browse the repository at this point in the history
* Pass the default ALC gchandle to the v3 preload hook

Fixes crashes early during startup when the gchandle is then used by the hooks
to call mono API functions.  The default ALC exists, but its managed object
doesn't, so the gchandle target is null.  The mono APIs detect the the special
gchandle and resolve it to the default ALC

Example crash
https://gist.github.com/grendello/b4ab24587a055725cc5e1416b86ad7ca

* [alc] Assert that we never see a null target from a managed ALC gchandle
  • Loading branch information
lambdageek committed Jun 24, 2021
1 parent c88da29 commit db9cfd2
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/mono/mono/metadata/assembly-load-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ mono_alc_from_gchandle (MonoGCHandle alc_gchandle)

HANDLE_FUNCTION_ENTER ();
MonoManagedAssemblyLoadContextHandle managed_alc = MONO_HANDLE_CAST (MonoManagedAssemblyLoadContext, mono_gchandle_get_target_handle (alc_gchandle));
g_assert (!MONO_HANDLE_IS_NULL (managed_alc));
MonoAssemblyLoadContext *alc = MONO_HANDLE_GETVAL (managed_alc, native_assembly_load_context);
HANDLE_FUNCTION_RETURN_VAL (alc);
}
Expand Down
16 changes: 14 additions & 2 deletions src/mono/mono/metadata/assembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -1579,9 +1579,21 @@ invoke_assembly_preload_hook (MonoAssemblyLoadContext *alc, MonoAssemblyName *an
if (hook->version == 2)
assembly = hook->func.v2 (alc, aname, apath, hook->user_data, error);
else { // v3
MonoGCHandle strong_gchandle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (alc->gchandle), TRUE);
/*
* For the default ALC, pass the globally known gchandle (since it's never collectible, it's always a strong handle).
* For other ALCs, make a new strong handle that is passed to the caller.
* Early at startup, when the default ALC exists, but its managed object doesn't, so the default ALC gchandle points to null.
*/
gboolean needs_free = TRUE;
MonoGCHandle strong_gchandle;
if (mono_alc_is_default (alc)) {
needs_free = FALSE;
strong_gchandle = alc->gchandle;
} else
strong_gchandle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (alc->gchandle), TRUE);
assembly = hook->func.v3 (strong_gchandle, aname, apath, hook->user_data, error);
mono_gchandle_free_internal (strong_gchandle);
if (needs_free)
mono_gchandle_free_internal (strong_gchandle);
}
/* TODO: propagage error out to callers */
mono_error_assert_ok (error);
Expand Down

0 comments on commit db9cfd2

Please sign in to comment.