Skip to content

Commit d45ccfd

Browse files
Fix reflection-calling Set method on arrays (#107529)
The test added in #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.
1 parent c534080 commit d45ccfd

File tree

3 files changed

+28
-2
lines changed

3 files changed

+28
-2
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,32 @@ public static unsafe Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArray
120120
return Array.NewMultiDimArray(typeHandleForArrayType.ToMethodTable(), pImmutableLengths, lengths.Length);
121121
}
122122

123+
public static unsafe void SetArrayValue(Array array, int[] indices, object value)
124+
{
125+
MethodTable* elementMT = array.ElementMethodTable;
126+
127+
if (elementMT->IsPointer || elementMT->IsFunctionPointer)
128+
{
129+
Debug.Assert(value.GetMethodTable()->ValueTypeSize == IntPtr.Size);
130+
elementMT = value.GetMethodTable();
131+
}
132+
133+
if (elementMT->IsValueType)
134+
{
135+
Debug.Assert(value.GetMethodTable()->IsValueType && elementMT->ValueTypeSize == value.GetMethodTable()->ValueTypeSize);
136+
nint flattenedIndex = array.GetFlattenedIndex(indices);
137+
ref byte element = ref Unsafe.AddByteOffset(ref MemoryMarshal.GetArrayDataReference(array), (nuint)flattenedIndex * array.ElementSize);
138+
RuntimeImports.RhUnbox(value, ref element, elementMT);
139+
}
140+
else
141+
{
142+
RuntimeImports.RhCheckArrayStore(array, value);
143+
nint flattenedIndex = array.GetFlattenedIndex(indices);
144+
ref object element = ref Unsafe.Add(ref Unsafe.As<byte, object>(ref MemoryMarshal.GetArrayDataReference(array)), flattenedIndex);
145+
element = value;
146+
}
147+
}
148+
123149
public static IntPtr GetAllocateObjectHelperForType(RuntimeTypeHandle type)
124150
{
125151
return RuntimeImports.RhGetRuntimeHelperForType(type.ToMethodTable(), RuntimeHelperKind.AllocateObject);

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ private unsafe nint GetFlattenedIndex(int rawIndex)
727727
return rawIndex;
728728
}
729729

730-
private unsafe nint GetFlattenedIndex(ReadOnlySpan<int> indices)
730+
internal unsafe nint GetFlattenedIndex(ReadOnlySpan<int> indices)
731731
{
732732
// Checked by the caller
733733
Debug.Assert(indices.Length == Rank);

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ internal sealed override IEnumerable<RuntimeMethodInfo> SyntheticMethods
213213
for (int i = 0; i < rank; i++)
214214
indices[i] = (int)(args[i]);
215215
object value = args[rank];
216-
array.SetValue(value, indices);
216+
RuntimeAugments.SetArrayValue(array, indices, value);
217217
return null;
218218
}
219219
);

0 commit comments

Comments
 (0)