Skip to content

Commit

Permalink
Fix reflection-calling Set method on arrays (dotnet#107529)
Browse files Browse the repository at this point in the history
The test added in dotnet#106787 found an issue in the implementation of reflection calls to array `Set` methods. We used to throw the wrong exception type. There were probably other corner case bugs (like what exception is thrown when both element type is wrong and index is out of range and when/how value coercion should happen). This should fix that.
  • Loading branch information
MichalStrehovsky authored Sep 9, 2024
1 parent c534080 commit d45ccfd
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,32 @@ public static unsafe Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArray
return Array.NewMultiDimArray(typeHandleForArrayType.ToMethodTable(), pImmutableLengths, lengths.Length);
}

public static unsafe void SetArrayValue(Array array, int[] indices, object value)
{
MethodTable* elementMT = array.ElementMethodTable;

if (elementMT->IsPointer || elementMT->IsFunctionPointer)
{
Debug.Assert(value.GetMethodTable()->ValueTypeSize == IntPtr.Size);
elementMT = value.GetMethodTable();
}

if (elementMT->IsValueType)
{
Debug.Assert(value.GetMethodTable()->IsValueType && elementMT->ValueTypeSize == value.GetMethodTable()->ValueTypeSize);
nint flattenedIndex = array.GetFlattenedIndex(indices);
ref byte element = ref Unsafe.AddByteOffset(ref MemoryMarshal.GetArrayDataReference(array), (nuint)flattenedIndex * array.ElementSize);
RuntimeImports.RhUnbox(value, ref element, elementMT);
}
else
{
RuntimeImports.RhCheckArrayStore(array, value);
nint flattenedIndex = array.GetFlattenedIndex(indices);
ref object element = ref Unsafe.Add(ref Unsafe.As<byte, object>(ref MemoryMarshal.GetArrayDataReference(array)), flattenedIndex);
element = value;
}
}

public static IntPtr GetAllocateObjectHelperForType(RuntimeTypeHandle type)
{
return RuntimeImports.RhGetRuntimeHelperForType(type.ToMethodTable(), RuntimeHelperKind.AllocateObject);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ private unsafe nint GetFlattenedIndex(int rawIndex)
return rawIndex;
}

private unsafe nint GetFlattenedIndex(ReadOnlySpan<int> indices)
internal unsafe nint GetFlattenedIndex(ReadOnlySpan<int> indices)
{
// Checked by the caller
Debug.Assert(indices.Length == Rank);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ internal sealed override IEnumerable<RuntimeMethodInfo> SyntheticMethods
for (int i = 0; i < rank; i++)
indices[i] = (int)(args[i]);
object value = args[rank];
array.SetValue(value, indices);
RuntimeAugments.SetArrayValue(array, indices, value);
return null;
}
);
Expand Down

0 comments on commit d45ccfd

Please sign in to comment.