Skip to content

Commit

Permalink
Throw InvalidOperationException on RuntimeMethodHandle.GetFunctionPoi…
Browse files Browse the repository at this point in the history
…nter() for generic methods (#104644)

* Throw InvalidOperationException on RuntimeMethodHandle.GetFunctionPointer() for generic methods

* Also check if owning type is generic; add checks to mono interpreter

* Update src/coreclr/vm/method.cpp

---------

Co-authored-by: Buyaa Namnan <[email protected]>
  • Loading branch information
steveharter and buyaa-n authored Jul 16, 2024
1 parent 5e7de53 commit 9565550
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 3 deletions.
5 changes: 2 additions & 3 deletions src/coreclr/vm/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2136,10 +2136,9 @@ PCODE MethodDesc::TryGetMultiCallableAddrOfCode(CORINFO_ACCESS_FLAGS accessFlags
}
CONTRACTL_END

if (IsGenericMethodDefinition())
if (ContainsGenericVariables())
{
_ASSERTE(!"Cannot take the address of an uninstantiated generic method.");
COMPlusThrow(kInvalidProgramException);
COMPlusThrow(kInvalidOperationException, IDS_EE_CODEEXECUTION_CONTAINSGENERICVAR);
}

if (accessFlags & CORINFO_ACCESS_LDFTN)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,39 @@ public void InvokeUninstantiatedGenericMethod()
Assert.Throws<InvalidOperationException>(() => GetMethod(typeof(MI_SubClass), nameof(MI_SubClass.StaticGenericMethod)).Invoke(null, [null]));
}

[Fact]
public void InvokeUninstantiatedGenericType_GenericMethod()
{
Assert.Throws<InvalidOperationException>(() => GetMethod(typeof(MI_GenericClass<>), "GenericMethod4").Invoke(null, [null]));
}

[Fact]
public void InvokeUninstantiatedGenericType_NonGenericMethod()
{
Assert.Throws<InvalidOperationException>(() => GetMethod(typeof(MI_GenericClass<>), "NonGenericMethod").Invoke(null, [null]));
}

[Fact]
public void GetFunctionPointerFromUninstantiatedGenericMethod()
{
RuntimeMethodHandle handle = typeof(MI_SubClass).GetMethod(nameof(MI_SubClass.StaticGenericMethod))!.MethodHandle;
Assert.Throws<InvalidOperationException>(() => handle.GetFunctionPointer());
}

[Fact]
public void GetFunctionPointerOnUninstantiatedGenericType_GenericMethod()
{
RuntimeMethodHandle handle = typeof(MI_GenericClass<>).GetMethod("GenericMethod4")!.MethodHandle;
Assert.Throws<InvalidOperationException>(() => handle.GetFunctionPointer());
}

[Fact]
public void GetFunctionPointerOnUninstantiatedGenericType_NonGenericMethod()
{
RuntimeMethodHandle handle = typeof(MI_GenericClass<>).GetMethod("NonGenericMethod")!.MethodHandle;
Assert.Throws<InvalidOperationException>(() => handle.GetFunctionPointer());
}

[Fact]
public void GetHashCodeTest()
{
Expand Down Expand Up @@ -799,6 +832,8 @@ public class MI_GenericClass<T>
public T GenericMethod1(T t) => t;
public T GenericMethod2<S>(S s1, T t, string s2) => t;
public static S GenericMethod3<S>(S s) => s;
public static T GenericMethod4(T s) => s;
public static void NonGenericMethod() { }
}

public interface MethodInfoBaseDefinitionInterface
Expand Down
5 changes: 5 additions & 0 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -7476,6 +7476,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;

MonoMethod *local_cmethod = LOCAL_VAR (ip [2], MonoMethod*);

if (local_cmethod->is_generic || mono_class_is_gtd (local_cmethod->klass)) {
MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidOperationException", "");
THROW_EX (ex, ip);
}

// FIXME push/pop LMF
if (G_UNLIKELY (mono_method_has_unmanaged_callers_only_attribute (local_cmethod))) {
local_cmethod = mono_marshal_get_managed_wrapper (local_cmethod, NULL, (MonoGCHandle)0, error);
Expand Down
5 changes: 5 additions & 0 deletions src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -2939,6 +2939,11 @@ mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
static gpointer
get_ftnptr_for_method (MonoMethod *method, gboolean need_unbox, MonoError *error)
{
if (method->is_generic || mono_class_is_gtd (method->klass)) {
mono_error_set_generic_error (error, "System", "InvalidOperationException", "");
return NULL;
}

if (!mono_llvm_only) {
gpointer res = mono_jit_compile_method (method, error);
res = mini_add_method_trampoline (method, res, mono_method_needs_static_rgctx_invoke (method, TRUE), need_unbox);
Expand Down

0 comments on commit 9565550

Please sign in to comment.