Skip to content
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 @@ -3974,6 +3974,11 @@ internal object GetUninitializedObject()
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this));
}

if (IsByRefLike)
{
throw new NotSupportedException(SR.NotSupported_ByRefLike);
}

// Compat: allocation always takes place outside the try block so that OOMs
// bubble up to the caller; the ctor invocation is within the try block so
// that it can be wrapped in TIE if needed.
Expand All @@ -3996,6 +4001,8 @@ internal object GetUninitializedObject()
[DebuggerHidden]
internal object? CreateInstanceOfT()
{
Debug.Assert(!IsValueType);

ActivatorCache cache = GetOrCreateCacheEntry<ActivatorCache>();

if (!cache.CtorIsPublic)
Expand Down
16 changes: 10 additions & 6 deletions src/coreclr/vm/reflectioninvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1475,11 +1475,13 @@ extern "C" void QCALLTYPE ReflectionInvocation_GetGuid(MethodTable* pMT, GUID* r
* doesn't guarantee that a ctor will succeed, only that the VM is able
* to support an instance of this type on the heap.
* ==========
* The 'allowByRefLike' parameter controls whether the type should be validated as not ByRefLike.
* The 'fForGetUninitializedInstance' parameter controls the type of
* exception that is thrown if a check fails.
*/
void RuntimeTypeHandle::ValidateTypeAbleToBeInstantiated(
static void ValidateTypeAbleToBeInstantiated(
TypeHandle typeHandle,
bool allowByRefLike,
bool fGetUninitializedObject)
{
STANDARD_VM_CONTRACT;
Expand Down Expand Up @@ -1535,14 +1537,14 @@ void RuntimeTypeHandle::ValidateTypeAbleToBeInstantiated(
}

// Don't allow ref structs
if (pMT->IsByRefLike())
if (!allowByRefLike && pMT->IsByRefLike())
{
COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike"));
}
}

/*
* Given a RuntimeType, queries info on how to instantiate the object.
* Given a RuntimeType, queries info on how to instantiate the type.
* pRuntimeType - [required] the RuntimeType object
* ppfnAllocator - [required, null-init] fnptr to the allocator
* mgd sig: void* -> object
Expand Down Expand Up @@ -1593,7 +1595,7 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_GetActivationInfo(
typeHandle = ((REFLECTCLASSBASEREF)pRuntimeType.Get())->GetType();
}

RuntimeTypeHandle::ValidateTypeAbleToBeInstantiated(typeHandle, false /* fGetUninitializedObject */);
ValidateTypeAbleToBeInstantiated(typeHandle, true /* allowByRefLike */, false /* fGetUninitializedObject */);

MethodTable* pMT = typeHandle.AsMethodTable();
_ASSERTE(pMT != NULL);
Expand Down Expand Up @@ -1746,7 +1748,8 @@ extern "C" void QCALLTYPE ReflectionSerialization_GetCreateUninitializedObjectIn

TypeHandle type = pType.AsTypeHandle();

RuntimeTypeHandle::ValidateTypeAbleToBeInstantiated(type, true /* fForGetUninitializedInstance */);
// ByRefLike types can't be boxed (allocated as an uninitialized object).
ValidateTypeAbleToBeInstantiated(type, false /* allowRefLike */, true /* fForGetUninitializedInstance */);

MethodTable* pMT = type.AsMethodTable();

Expand Down Expand Up @@ -1919,7 +1922,8 @@ extern "C" void QCALLTYPE ReflectionInvocation_GetBoxInfo(

TypeHandle type = pType.AsTypeHandle();

RuntimeTypeHandle::ValidateTypeAbleToBeInstantiated(type, true /* fForGetUninitializedInstance */);
// ByRefLike types can't be boxed.
ValidateTypeAbleToBeInstantiated(type, false /* allowRefLike */, true /* fForGetUninitializedInstance */);

MethodTable* pMT = type.AsMethodTable();

Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,6 @@ class RuntimeTypeHandle

static FCDECL1(MethodDesc *, GetFirstIntroducedMethod, ReflectClassBaseObject* pType);
static FCDECL1(void, GetNextIntroducedMethod, MethodDesc **ppMethod);

// Helper methods not called by managed code

static void ValidateTypeAbleToBeInstantiated(TypeHandle typeHandle, bool fGetUninitializedObject);
};

extern "C" void QCALLTYPE RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow(void* typeHandleRaw, QCall::ObjectHandleOnStack result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public static partial class Activator

// Casting the above object to T is technically invalid because
// T can be ByRefLike (that is, ref struct). Roslyn blocks the
// cast this in function with a "CS0030: Cannot convert type 'object' to 'T'",
// cast in this function with a "CS0030: Cannot convert type 'object' to 'T'",
// which is correct. However, since we are doing the IsValueType
// check above, we know this code path will only be taken with
// reference types and therefore the below Unsafe.As<> is safe.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
Expand Down Expand Up @@ -94,6 +95,28 @@ public void CreateInstance_NonPublicTypeWithPrivateDefaultConstructor_Success()
Assert.Equal(-1, c2.Property);
}

// Add attribute to avoid unused field warning
[StructLayout(LayoutKind.Sequential)]
ref struct RSNoCtor
{
public int Value;
}

ref struct RSCtor
{
public int Value;
public RSCtor() => Value = 10;
}

[Fact]
public void CreateInstance_ByRefTypeAsGenericParameter_Success()
{
Assert.Equal(0, Activator.CreateInstance<Span<int>>().Length);
Assert.Equal(0, Activator.CreateInstance<ReadOnlySpan<string>>().Length);
Assert.Equal(0, Activator.CreateInstance<RSNoCtor>().Value);
Assert.Equal(10, Activator.CreateInstance<RSCtor>().Value);
}

[Fact]
public void CreateInstance_PublicOnlyTypeWithPrivateDefaultConstructor_ThrowsMissingMethodException()
{
Expand Down Expand Up @@ -318,17 +341,15 @@ public void CreateInstance_AbstractClass_ThrowsMissingMemberException(Type type)
[Theory]
[InlineData(typeof(TypedReference))]
[InlineData(typeof(RuntimeArgumentHandle))]
[InlineData(typeof(Span<int>))]
[InlineData(typeof(ReadOnlySpan<string>))]
[InlineData(typeof(RSNoCtor))]
[InlineData(typeof(RSCtor))]
public void CreateInstance_BoxedByRefType_ThrowsNotSupportedException(Type type)
{
Assert.Throws<NotSupportedException>(() => Activator.CreateInstance(type));
}

[Fact]
public void CreateInstance_Span_ThrowsNotSupportedException()
{
CreateInstance_BoxedByRefType_ThrowsNotSupportedException(typeof(Span<int>));
}

[Fact]
public void CreateInstance_InterfaceType_ThrowsMissingMemberException()
{
Expand Down
Loading