Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR feedback #12

Merged
merged 1 commit into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,14 @@ internal static bool HasElementType(RuntimeType type)
/// MethodTable* corresponding to that type. If the type is <see cref="Nullable{T}"/> closed over
/// some T and <paramref name="unwrapNullable"/> is true, then returns the values for the 'T'.
/// </summary>
internal static delegate*<MethodTable*, object> GetNewobjHelperFnPtr(RuntimeType type, out MethodTable* pMT, bool unwrapNullable, bool allowCom)
internal static delegate*<MethodTable*, object> GetNewobjHelperFnPtr(
// This API doesn't call any constructors, but the type needs to be seen as constructed.
// A type is seen as constructed if a constructor is kept.
// This obviously won't cover a type with no constructor. Reference types with no
// constructor are an academic problem. Valuetypes with no constructors are a problem,
// but IL Linker currently treats them as always implicitly boxed.
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] RuntimeType type,
out MethodTable* pMT, bool unwrapNullable, bool allowCom)
{
Debug.Assert(type != null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3971,24 +3971,26 @@ public void EnsureInitialized(RuntimeType type)

Debug.Assert(cache._pfnNewobj != null);
Debug.Assert(cache._pfnCtor != null);
Debug.Assert(cache._pMT != null);

if (!cache._ctorIsPublic && publicOnly)
{
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this));
}

object? obj = cache._pfnNewobj(cache._pMT); // allocation outside the try block (allow OOM to bubble up)
GC.KeepAlive(this); // can't allow the type to be collected before the object is created

try
{
object? obj = cache._pfnNewobj(cache._pMT);
GC.KeepAlive(this); // can't allow the type to be collected before the object is created

cache._pfnCtor(obj);
return obj;
}
catch (Exception e) when (wrapExceptions)
{
throw new TargetInvocationException(e);
}

return obj;
}

if (!skipCheckThis)
Expand Down
13 changes: 6 additions & 7 deletions src/coreclr/src/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ FCIMPLEND
* throws an exception. If TypeHandle is a value type, the NEWOBJ helper will create
* a boxed zero-inited instance of the value type.
*/
void QCALLTYPE RuntimeTypeHandle::GetNewobjHelperFnPtr(
void QCALLTYPE RuntimeTypeHandle::GetNewobjHelperFnPtr(
QCall::TypeHandle pTypeHandle,
PCODE* ppNewobjHelper,
MethodTable** ppMT,
Expand Down Expand Up @@ -597,6 +597,8 @@ FCIMPLEND
MethodTable* pMT = typeHandle.AsMethodTable();
PREFIX_ASSUME(pMT != NULL);

pMT->EnsureInstanceActive();

// Don't allow creating instances of void or delegates
if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_VOID) || pMT->IsDelegate())
{
Expand Down Expand Up @@ -646,13 +648,10 @@ FCIMPLEND
pMT = pMT->GetInstantiation()[0].GetMethodTable();
}

// Ensure the type's cctor has run
Assembly* pAssem = pMT->GetAssembly();
if (!pMT->IsClassInited())
// Run the type's cctor if needed (if not marked beforefieldinit)
if (pMT->HasPreciseInitCctors())
{
pMT->CheckRestore();
pMT->EnsureInstanceActive();
pMT->CheckRunClassInitThrowing();
pMT->CheckRunClassInitAsIfConstructingThrowing();
}

// And we're done!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public static bool IsDrawingSupported
}

public static bool IsInContainer => GetIsInContainer();
public static bool SupportsComInterop => IsWindows && IsNetCore; // matches definitions in clr.featuredefines.props
public static bool SupportsSsl3 => GetSsl3Support();
public static bool SupportsSsl2 => IsWindows && !PlatformDetection.IsWindows10Version1607OrGreater;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,6 @@ public static IEnumerable<object[]> GetUninitializedObject_NegativeTestCases()
{
// TODO: Test actual function pointer types when typeof(delegate*<...>) support is available

Type canonType = typeof(object).Assembly.GetType("System.__Canon", throwOnError: true);

yield return new[] { typeof(string), typeof(ArgumentException) }; // variable-length type
yield return new[] { typeof(int[]), typeof(ArgumentException) }; // variable-length type
yield return new[] { typeof(int[,]), typeof(ArgumentException) }; // variable-length type
Expand All @@ -220,9 +218,14 @@ public static IEnumerable<object[]> GetUninitializedObject_NegativeTestCases()

yield return new[] { typeof(ReadOnlySpan<int>), typeof(NotSupportedException) }; // byref type
yield return new[] { typeof(ArgIterator), typeof(NotSupportedException) }; // byref type
yield return new[] { typeof(List<>).MakeGenericType(canonType), typeof(NotSupportedException) }; // shared by generic instantiations

if (PlatformDetection.IsWindows)
if (PlatformDetection.IsNetCore)
{
Type canonType = typeof(object).Assembly.GetType("System.__Canon", throwOnError: true);
yield return new[] { typeof(List<>).MakeGenericType(canonType), typeof(NotSupportedException) }; // shared by generic instantiations
}

if (PlatformDetection.SupportsComInterop)
{
Type comObjType = typeof(object).Assembly.GetType("System.__ComObject", throwOnError: true);
yield return new[] { comObjType, typeof(NotSupportedException) }; // COM type
Expand All @@ -238,6 +241,46 @@ internal class WbemContext
{
}

internal class ClassWithBeforeFieldInitCctor
{
private static readonly int _theInt = GetInt();

private static int GetInt()
{
AppDomain.CurrentDomain.SetData("ClassWithBeforeFieldInitCctor_CctorRan", true);
return 0;
}
}

internal class ClassWithNormalCctor
{
private static readonly int _theInt;

static ClassWithNormalCctor()
{
AppDomain.CurrentDomain.SetData("ClassWithNormalCctor_CctorRan", true);
_theInt = 0;
}
}

[Fact]
public static void GetUninitalizedObject_DoesNotRunBeforeFieldInitCctors()
{
object o = RuntimeHelpers.GetUninitializedObject(typeof(ClassWithBeforeFieldInitCctor));
Assert.IsType<ClassWithBeforeFieldInitCctor>(o);

Assert.Null(AppDomain.CurrentDomain.GetData("ClassWithBeforeFieldInitCctor_CctorRan"));
}

[Fact]
public static void GetUninitalizedObject_RunsNormalStaticCtors()
{
object o = RuntimeHelpers.GetUninitializedObject(typeof(ClassWithNormalCctor));
Assert.IsType<ClassWithNormalCctor>(o);

Assert.Equal(true, AppDomain.CurrentDomain.GetData("ClassWithNormalCctor_CctorRan"));
}

[Theory]
[MemberData(nameof(GetUninitializedObject_NegativeTestCases))]
public static void GetUninitializedObject_InvalidArguments_ThrowsException(Type typeToInstantiate, Type expectedExceptionType)
Expand Down