Skip to content

Commit

Permalink
Fix marshalling a pinnable multi-dimensional array via a P/Inv… (dotn…
Browse files Browse the repository at this point in the history
…et#26279)

* Use the exact methodtable of the parameter to calculate the offset into a pinned array.

* Fix logic check.

* Update precondition.

* Fix accidental union overlap.
  • Loading branch information
jkoritzinsky committed Aug 27, 2019
1 parent 501c1e3 commit f43185b
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 3 deletions.
8 changes: 5 additions & 3 deletions src/vm/ilmarshalers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3701,15 +3701,17 @@ void ILNativeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)

bool ILNativeArrayMarshaler::CanMarshalViaPinning()
{
return IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags) && (NULL == OleVariant::GetMarshalerForVarType(m_pargs->na.m_vt, TRUE));
// We can't pin an array if we have a marshaler for the var type
// or if we can't get a method-table representing the array (how we determine the offset to pin).
return IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags) && (NULL != m_pargs->na.m_pArrayMT) && (NULL == OleVariant::GetMarshalerForVarType(m_pargs->na.m_vt, TRUE));
}

void ILNativeArrayMarshaler::EmitMarshalViaPinning(ILCodeStream* pslILEmit)
{
CONTRACTL
{
STANDARD_VM_CHECK;
PRECONDITION(IsCLRToNative(m_dwMarshalFlags) && !IsByref(m_dwMarshalFlags));
PRECONDITION(CanMarshalViaPinning());
}
CONTRACTL_END;

Expand Down Expand Up @@ -3744,7 +3746,7 @@ void ILNativeArrayMarshaler::EmitMarshalViaPinning(ILCodeStream* pslILEmit)
pslILEmit->EmitCONV_I();
// Optimize marshalling by emitting the data ptr offset directly into the IL stream
// instead of doing an FCall to recalulate it each time when possible.
pslILEmit->EmitLDC(ArrayBase::GetDataPtrOffset(m_pargs->m_pMarshalInfo->GetArrayElementTypeHandle().MakeSZArray().GetMethodTable()));
pslILEmit->EmitLDC(ArrayBase::GetDataPtrOffset(m_pargs->na.m_pArrayMT));
pslILEmit->EmitADD();
EmitStoreNativeValue(pslILEmit);

Expand Down
2 changes: 2 additions & 0 deletions src/vm/mlinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2802,6 +2802,8 @@ MarshalInfo::MarshalInfo(Module* pModule,
}
}

m_args.na.m_pArrayMT = arrayTypeHnd.GetMethodTable();

// Handle retrieving the information for the array type.
IfFailGoto(HandleArrayElemType(&ParamInfo, thElement, asArray->GetRank(), mtype == ELEMENT_TYPE_SZARRAY, isParam, pAssembly), lFail);
break;
Expand Down
1 change: 1 addition & 0 deletions src/vm/mlinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct OverrideProcArgs

struct
{
MethodTable* m_pArrayMT;
VARTYPE m_vt;
#ifdef FEATURE_COMINTEROP
SIZE_T m_cbElementSize;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,12 +244,19 @@ private static extern bool CStyle_Array_Struct_Out(
[DllImport("MarshalArrayLPArrayNative")]
private static extern bool CStyle_Array_Bool_Out(
[Out] bool[] actual, int cActual);

[DllImport("MarshalArrayLPArrayNative")]
private static extern int Get_Multidimensional_Array_Sum(int[,] array, int rows, int columns);
#endregion

#region Marshal ByVal

private const int ARRAY_SIZE = 100;

private const int ROWS = 3;

private const int COLUMNS = 2;

private static T[] InitArray<T>(int size)
{
T[] array = new T[size];
Expand Down Expand Up @@ -290,6 +297,20 @@ private static TestStruct[] InitStructArray(int size)
return array;
}

private static int[,] InitMultidimensionalBlittableArray(int rows, int columns)
{
int[,] array = new int[rows, columns];

for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = i * j;
}
}
return array;
}

private static void TestMarshalByVal_NoAttributes()
{
Console.WriteLine("ByVal marshaling CLR array as c-style-array no attributes");
Expand Down Expand Up @@ -619,6 +640,19 @@ private static void TestMarshalOut_ByVal()

#endregion

private static void TestMultidimensional()
{
Console.WriteLine("================== [Get_Multidimensional_Array_Sum] ============");
int[,] array = InitMultidimensionalBlittableArray(ROWS, COLUMNS);
int sum = 0;
foreach (int item in array)
{
sum += item;
}

Assert.AreEqual(sum, Get_Multidimensional_Array_Sum(array, ROWS, COLUMNS));
}

public static int Main()
{
try
Expand All @@ -627,6 +661,7 @@ public static int Main()
TestMarshalByVal_In();
TestMarshalInOut_ByVal();
TestMarshalOut_ByVal();
TestMultidimensional();

Console.WriteLine("\nTest PASS.");
return 100;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1111,3 +1111,16 @@ extern "C" DLL_EXPORT BOOL MarshalArrayOfStructAsLPArrayByRefOut(S2 **pActual, i
}
return breturn;
}

extern "C" DLL_EXPORT int Get_Multidimensional_Array_Sum(int* array, int rows, int columns)
{
int sum = 0;
for(int i = 0; i < rows; ++i)
{
for (int j = 0; j < columns; ++j)
{
sum += array[i * columns + j];
}
}
return sum;
}

0 comments on commit f43185b

Please sign in to comment.