Skip to content

Commit

Permalink
Fix throwing exception when calling RunClassConstructor on a generic …
Browse files Browse the repository at this point in the history
…type with a static constructor (#105513)

* Fix throwing exception when calling RunClassConstructor on a generic type with a static constructor

#99183 seems to have done away with assuming that a generic type's static constructor was
always "initialized". As a result, if you call RunClassConstructor on it, the runtime would throw an exception.

Fixes #103891

* Apply suggestions from code review

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
steveisok and jkotas committed Jul 26, 2024
1 parent dc3ed0d commit 8ed5625
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/coreclr/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3768,6 +3768,8 @@ void MethodTable::CheckRunClassInitThrowing()
if (IsSharedByGenericInstantiations())
return;

_ASSERTE(!ContainsGenericVariables());

EnsureStaticDataAllocated();
DoRunClassInitThrowing();
}
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1306,7 +1306,8 @@ extern "C" void QCALLTYPE ReflectionInvocation_RunClassConstructor(QCall::TypeHa
return;

MethodTable *pMT = typeHnd.AsMethodTable();
if (pMT->IsClassInited())
// The ContainsGenericVariables check is to preserve back-compat where we assume the generic type is already initialized
if (pMT->IsClassInited() || pMT->ContainsGenericVariables())
return;

BEGIN_QCALL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using Xunit;

namespace System.Runtime.CompilerServices.Tests
Expand Down Expand Up @@ -101,7 +102,8 @@ public static void RunClassConstructor()
RuntimeTypeHandle t = typeof(HasCctor).TypeHandle;
RuntimeHelpers.RunClassConstructor(t);
Assert.Equal("Hello", HasCctorReceiver.S);
return;
// Should not throw
RuntimeHelpers.RunClassConstructor(typeof(GenericHasCctor<>).TypeHandle);
}

internal class HasCctor
Expand All @@ -117,6 +119,14 @@ internal class HasCctorReceiver
public static string S;
}

internal class GenericHasCctor<T>
{
static GenericHasCctor()
{
Thread.Yield(); // Make sure the preinitialization optimization doesn't eat this.
}
}

[Fact]
public static void PrepareMethod()
{
Expand Down

0 comments on commit 8ed5625

Please sign in to comment.