MarshalAs(UnManaged.ByValArray) overflow.
authorTijoy Tom Kalathiparambil <tijoytk@microsoft.com>
Thu, 7 Jul 2016 22:03:01 +0000 (15:03 -0700)
committerTijoy Tom Kalathiparambil <tijoytk@microsoft.com>
Thu, 7 Jul 2016 22:03:01 +0000 (15:03 -0700)
For non-blittable embedded array in structs we ignored the SizeConst and wrote past the
buffer when number of elementsin the arrayis greater than SizeConst.Fix is to truncate
the array at SizeConst
MarshalAs(UnManaged.ByValTStr)
Very subtle case when the SizeConst == Number of bytes required to marshal , we
write the null one past the buffer.This happens only on  machine with non-english
(multi-byte) locale as default. Fix is to check the number of bytes required and
truncate the correctly leaving space for the terminating null.

Commit migrated from https://github.com/dotnet/coreclr/commit/8d51b631b3f582a093a108acfa28c2390fe85f41

14 files changed:
src/coreclr/src/vm/fieldmarshaler.cpp
src/coreclr/src/vm/ilmarshalers.cpp
src/coreclr/src/vm/olevariant.cpp
src/coreclr/src/vm/olevariant.h
src/coreclr/tests/src/Interop/CMakeLists.txt
src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.cs [new file with mode: 0644]
src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.csproj [new file with mode: 0644]
src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/project.json [new file with mode: 0644]
src/coreclr/tests/src/Interop/SizeConst/CMakeLists.txt [new file with mode: 0644]
src/coreclr/tests/src/Interop/SizeConst/SizeConstNative.cpp [new file with mode: 0644]
src/coreclr/tests/src/Interop/SizeConst/SizeConstTest.cs [new file with mode: 0644]
src/coreclr/tests/src/Interop/SizeConst/SizeConstTest.csproj [new file with mode: 0644]
src/coreclr/tests/src/Interop/SizeConst/project.json [new file with mode: 0644]
src/coreclr/tests/testsUnsupportedOutsideWindows.txt

index 23cbe18..a1904e0 100644 (file)
@@ -3364,14 +3364,22 @@ VOID FieldMarshaler_FixedStringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVO
             nc = m_numchar - 1;
 
         int cbwritten = InternalWideToAnsi(pString->GetBuffer(),
-                                           nc,
-                                            (CHAR*)pNativeValue,
-                                           m_numchar,
-                                           m_BestFitMap,
-                                           m_ThrowOnUnmappableChar);
+            nc,
+            (CHAR*)pNativeValue,
+            m_numchar,
+            m_BestFitMap,
+            m_ThrowOnUnmappableChar);
+
+        // Handle the case where SizeConst == Number of bytes.For single byte chars 
+        // this will never be the case since nc >= m_numchar check will truncate the last 
+        // character, but for multibyte chars nc>= m_numchar check won't truncate since GetStringLength
+        // gives number of characters but not the actual number of bytes. For such cases need to make 
+        // sure that we dont write one past the buffer.
+        if (cbwritten == m_numchar)
+            --cbwritten;
+
         ((CHAR*)pNativeValue)[cbwritten] = '\0';
     }
-
 }
 
 
@@ -3572,10 +3580,10 @@ VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pN
     }
     else
     {
-        // Make sure the size of the array is the same as specified in the MarshalAs attribute (via the SizeConst field).
+        // Make sure the size of the array is >= as specified in the MarshalAs attribute (via the SizeConst field).
         if ((*pCLRValue)->GetNumComponents() < m_numElems)
             COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
-
+  
         // Marshal the contents from the managed array to the native array.
         const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);  
         if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
@@ -3588,7 +3596,7 @@ VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pN
 
             // We never operate on an uninitialized native layout here, we have zero'ed it if needed.
             // Therefore fOleArrayIsValid is always TRUE.
-            pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE);
+            pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE, m_numElems);
         }
     }
 }
index ebd8250..114fbe3 100644 (file)
@@ -4372,20 +4372,19 @@ FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToNative, MngdNativeArray
     if (*pArrayRef != NULL)
     {
         const OleVariant::Marshaler* pMarshaler = OleVariant::GetMarshalerForVarType(pThis->m_vt, TRUE);
-    
+        SIZE_T cElements = (*pArrayRef)->GetNumComponents();
         if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
         {
-            SIZE_T cElements = (*pArrayRef)->GetNumComponents();
-            SIZE_T cbArray = cElements;
-            if ( (!SafeMulSIZE_T(&cbArray, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cbArray > MAX_SIZE_FOR_INTEROP)
+            if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
                 COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
     
             _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
-            memcpyNoGCRefs(*pNativeHome, (*pArrayRef)->GetDataPtr(), cbArray);
+            memcpyNoGCRefs(*pNativeHome, (*pArrayRef)->GetDataPtr(), cElements);
         }
         else
         {
-            pMarshaler->ComToOleArray(pArrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap, pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid);
+            pMarshaler->ComToOleArray(pArrayRef, *pNativeHome, pThis->m_pElementMT, pThis->m_BestFitMap, 
+                                      pThis->m_ThrowOnUnmappableChar, pThis->m_NativeDataValid, cElements);
         }
     }
     HELPER_METHOD_FRAME_END();
@@ -4437,13 +4436,12 @@ FCIMPL3(void, MngdNativeArrayMarshaler::ConvertContentsToManaged, MngdNativeArra
         if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
         {
             SIZE_T cElements = (*pArrayRef)->GetNumComponents();
-            SIZE_T cbArray = cElements;
-            if ( (!SafeMulSIZE_T(&cbArray, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cbArray > MAX_SIZE_FOR_INTEROP)
+            if ( (!SafeMulSIZE_T(&cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT))) || cElements > MAX_SIZE_FOR_INTEROP)
                 COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE);
     
                 // If we are copying variants, strings, etc, we need to use write barrier
             _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsPointers());
-            memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), *pNativeHome, cbArray );
+            memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), *pNativeHome, cElements);
         }
         else
         {
index ccf90a3..75483fd 100644 (file)
@@ -1275,7 +1275,8 @@ void OleVariant::MarshalBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArra
 
 void OleVariant::MarshalBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                           MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                          BOOL fThrowOnUnmappableChar,
+                                          BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -1288,10 +1289,9 @@ void OleVariant::MarshalBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArra
     CONTRACTL_END;
     
     ASSERT_PROTECTED(pComArray);
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
 
     VARIANT_BOOL *pOle = (VARIANT_BOOL *) oleArray;
-    VARIANT_BOOL *pOleEnd = pOle + elementCount;
+    VARIANT_BOOL *pOleEnd = pOle + cElements;
     
     UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
 
@@ -1365,7 +1365,8 @@ void OleVariant::MarshalWinBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComA
 
 void OleVariant::MarshalWinBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                           MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                          BOOL fThrowOnUnmappableChar, 
+                                          BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -1378,10 +1379,9 @@ void OleVariant::MarshalWinBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleA
     CONTRACTL_END;
     
     ASSERT_PROTECTED(pComArray);
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
 
     BOOL *pOle = (BOOL *) oleArray;
-    BOOL *pOleEnd = pOle + elementCount;
+    BOOL *pOleEnd = pOle + cElements;
     
     UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
 
@@ -1455,7 +1455,8 @@ void OleVariant::MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArr
 
 void OleVariant::MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                         MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                        BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                        BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+                                        SIZE_T cElements)
 {
     LIMITED_METHOD_CONTRACT;
       
@@ -1472,10 +1473,9 @@ void OleVariant::MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArr
     ASSERT_PROTECTED(pComArray);
     
     _ASSERTE((*pComArray)->GetArrayElementType() == ELEMENT_TYPE_BOOLEAN);
-
-    SIZE_T cbArray = (*pComArray)->GetNumComponents();
+        
     BYTE *pOle = (BYTE *) oleArray;
-    BYTE *pOleEnd = pOle + cbArray;
+    BYTE *pOleEnd = pOle + cElements;
     
     UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
       
@@ -1554,7 +1554,8 @@ void OleVariant::MarshalAnsiCharArrayOleToCom(void *oleArray, BASEARRAYREF *pCom
 
 void OleVariant::MarshalAnsiCharArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                           MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+                                          SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -1565,15 +1566,13 @@ void OleVariant::MarshalAnsiCharArrayComToOle(BASEARRAYREF *pComArray, void *ole
         PRECONDITION(CheckPointer(pComArray));
     }
     CONTRACTL_END;
-    
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
 
     const WCHAR *pCom = (const WCHAR *) (*pComArray)->GetDataPtr();
 
-    if (!FitsIn<int>(elementCount))
+    if (!FitsIn<int>(cElements))
         COMPlusThrowHR(COR_E_OVERFLOW);
 
-    int cchCount = (int)elementCount;
+    int cchCount = (int)cElements;
     int cbBuffer;
 
     if (!ClrSafeInt<int>::multiply(cchCount, GetMaxDBCSCharByteSize(), cbBuffer))
@@ -1774,11 +1773,12 @@ void OleVariant::MarshalInterfaceArrayOleToCom(void *oleArray, BASEARRAYREF *pCo
 
 void OleVariant::MarshalIUnknownArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                               MethodTable *pElementMT, BOOL fBestFitMapping,
-                                              BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                              BOOL fThrowOnUnmappableChar, 
+                                              BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     WRAPPER_NO_CONTRACT;
     
-    MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, FALSE);
+    MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, FALSE, cElements);
 }
 
 void OleVariant::ClearInterfaceArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
@@ -1919,7 +1919,8 @@ void OleVariant::MarshalBSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArra
 
 void OleVariant::MarshalBSTRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                           MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                          BOOL fThrowOnUnmappableChar, 
+                                          BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -1937,10 +1938,8 @@ void OleVariant::MarshalBSTRArrayComToOle(BASEARRAYREF *pComArray, void *oleArra
     {
     ASSERT_PROTECTED(pComArray);
 
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
     BSTR *pOle = (BSTR *) oleArray;
-    BSTR *pOleEnd = pOle + elementCount;
+    BSTR *pOleEnd = pOle + cElements;
 
     STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
 
@@ -2021,7 +2020,8 @@ void OleVariant::MarshalNonBlittableRecordArrayOleToCom(void *oleArray, BASEARRA
 
 void OleVariant::MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                           MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                          BOOL fThrowOnUnmappableChar, 
+                                          BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -2035,12 +2035,11 @@ void OleVariant::MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF *pComArray,
     CONTRACTL_END;
     
     ASSERT_PROTECTED(pComArray);
-
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
+    
     SIZE_T elemSize     = pInterfaceMT->GetNativeSize();
 
     BYTE *pOle = (BYTE *) oleArray;
-    BYTE *pOleEnd = pOle + elemSize * elementCount;
+    BYTE *pOleEnd = pOle + elemSize * cElements;
 
     if (!fOleArrayIsValid)
     {
@@ -2140,7 +2139,8 @@ void OleVariant::MarshalLPWSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComAr
 
 void OleVariant::MarshalLPWSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                              MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                             BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                             BOOL fThrowOnUnmappableChar, 
+                                             BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -2155,10 +2155,8 @@ void OleVariant::MarshalLPWSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleA
 
     ASSERT_PROTECTED(pComArray);
 
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
     LPWSTR *pOle = (LPWSTR *) oleArray;
-    LPWSTR *pOleEnd = pOle + elementCount;
+    LPWSTR *pOleEnd = pOle + cElements;
 
     STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
 
@@ -2281,7 +2279,8 @@ void OleVariant::MarshalLPSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArr
 
 void OleVariant::MarshalLPSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                             MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                            BOOL fThrowOnUnmappableChar, 
+                                            BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -2296,10 +2295,8 @@ void OleVariant::MarshalLPSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleAr
 
     ASSERT_PROTECTED(pComArray);
 
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
     LPSTR *pOle = (LPSTR *) oleArray;
-    LPSTR *pOleEnd = pOle + elementCount;
+    LPSTR *pOleEnd = pOle + cElements;
 
     STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
 
@@ -2425,7 +2422,8 @@ void OleVariant::MarshalDateArrayOleToCom(void *oleArray, BASEARRAYREF *pComArra
 
 void OleVariant::MarshalDateArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                           MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                          BOOL fThrowOnUnmappableChar, 
+                                          BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -2438,11 +2436,9 @@ void OleVariant::MarshalDateArrayComToOle(BASEARRAYREF *pComArray, void *oleArra
     CONTRACTL_END;
     
     ASSERT_PROTECTED(pComArray);
-
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
-
+    
     DATE *pOle = (DATE *) oleArray;
-    DATE *pOleEnd = pOle + elementCount;
+    DATE *pOleEnd = pOle + cElements;
     
     INT64 *pCom = (INT64 *) (*pComArray)->GetDataPtr();
 
@@ -2661,7 +2657,8 @@ void OleVariant::MarshalRecordArrayOleToCom(void *oleArray, BASEARRAYREF *pComAr
 
 void OleVariant::MarshalRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                             MethodTable *pElementMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                            BOOL fThrowOnUnmappableChar, 
+                                            BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -2684,15 +2681,14 @@ void OleVariant::MarshalRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleAr
     {
         // The array is blittable so we can simply copy it.
         _ASSERTE(pComArray);
-        SIZE_T elementCount = (*pComArray)->GetNumComponents();
         SIZE_T elemSize     = pElementMT->GetNativeSize();
-        memcpyNoGCRefs(oleArray, (*pComArray)->GetDataPtr(), elementCount * elemSize);
+        memcpyNoGCRefs(oleArray, (*pComArray)->GetDataPtr(), cElements * elemSize);
     }
     else
     {
         // The array is non blittable so we need to marshal the elements.
         _ASSERTE(pElementMT->HasLayout());
-        MarshalNonBlittableRecordArrayComToOle(pComArray, oleArray, pElementMT, fBestFitMapping, fThrowOnUnmappableChar, fOleArrayIsValid);
+        MarshalNonBlittableRecordArrayComToOle(pComArray, oleArray, pElementMT, fBestFitMapping, fThrowOnUnmappableChar, fOleArrayIsValid, cElements);
     }
 }
 
@@ -3607,7 +3603,8 @@ void OleVariant::MarshalOleVariantForComVariant(VariantData *pCom, VARIANT *pOle
 }
 
 void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, void *oleArray,
-                                                     MethodTable *pElementMT, BOOL bDefaultIsDispatch)
+                                                     MethodTable *pElementMT, BOOL bDefaultIsDispatch,
+                                                     SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -3620,7 +3617,7 @@ void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, vo
     CONTRACTL_END;
    
     ASSERT_PROTECTED(pComArray);
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
+    
 
     BOOL bDispatch = bDefaultIsDispatch;
     BOOL bHeterogenous = (pElementMT == NULL);
@@ -3638,7 +3635,7 @@ void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, vo
 
     // Determine the start and the end of the data in the OLE array.
     IUnknown **pOle = (IUnknown **) oleArray;
-    IUnknown **pOleEnd = pOle + elementCount;
+    IUnknown **pOleEnd = pOle + cElements;
 
     // Retrieve the start of the data in the managed array.
     BASEARRAYREF unprotectedArray = *pComArray;
@@ -3787,11 +3784,12 @@ HRESULT OleVariant::ClearAndInsertContentsIntoByrefRecordVariant(VARIANT* pOle,
 
 void OleVariant::MarshalIDispatchArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                                MethodTable *pElementMT, BOOL fBestFitMapping,
-                                               BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                               BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+                                               SIZE_T cElements)
 {
     WRAPPER_NO_CONTRACT;
     
-    MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, TRUE);
+    MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, TRUE, cElements);
 }
 
 
@@ -3913,7 +3911,8 @@ void OleVariant::MarshalCurrencyArrayOleToCom(void *oleArray, BASEARRAYREF *pCom
 
 void OleVariant::MarshalCurrencyArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                               MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                              BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                              BOOL fThrowOnUnmappableChar, 
+                                              BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -3925,11 +3924,10 @@ void OleVariant::MarshalCurrencyArrayComToOle(BASEARRAYREF *pComArray, void *ole
     }
     CONTRACTL_END;
 
-    ASSERT_PROTECTED(pComArray);
-    SIZE_T elementCount = (*pComArray)->GetNumComponents();
+    ASSERT_PROTECTED(pComArray);    
 
     CURRENCY *pOle = (CURRENCY *) oleArray;
-    CURRENCY *pOleEnd = pOle + elementCount;
+    CURRENCY *pOleEnd = pOle + cElements;
     
     DECIMAL *pCom = (DECIMAL *) (*pComArray)->GetDataPtr();
 
@@ -3992,7 +3990,8 @@ void OleVariant::MarshalVariantArrayOleToCom(void *oleArray, BASEARRAYREF *pComA
 
 void OleVariant::MarshalVariantArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
                                              MethodTable *pInterfaceMT, BOOL fBestFitMapping,
-                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+                                             BOOL fThrowOnUnmappableChar, 
+                                             BOOL fOleArrayIsValid, SIZE_T cElements)
 {
     CONTRACTL
     {
@@ -4607,9 +4606,9 @@ void OleVariant::MarshalSafeArrayForArrayRef(BASEARRAYREF *pArrayRef,
                     // of UnknownWrapper or DispatchWrapper. It shall use a different logic and marshal each
                     // element according to its specific default interface.
                     pInterfaceMT = NULL;
-               }
-                   marshal->ComToOleArray(&Array, pSafeArray->pvData, pInterfaceMT, TRUE, FALSE, fSafeArrayIsValid);
-           }                   
+                }
+                marshal->ComToOleArray(&Array, pSafeArray->pvData, pInterfaceMT, TRUE, FALSE, fSafeArrayIsValid, dwNumComponents);
+            }
             
             if (pSafeArray->cDims != 1)
             {
index c733103..b89ace9 100644 (file)
@@ -433,7 +433,8 @@ class OleVariant
 
     // Helper called from MarshalIUnknownArrayComToOle and MarshalIDispatchArrayComToOle.
     static void MarshalInterfaceArrayComToOleHelper(BASEARRAYREF* pComArray, void* oleArray,
-                                                    MethodTable* pElementMT, BOOL bDefaultIsDispatch);
+                                                    MethodTable* pElementMT, BOOL bDefaultIsDispatch,
+                                                    SIZE_T cElements);
 #endif // FEATURE_COMINTEROP
     
     struct Marshaler
@@ -445,7 +446,8 @@ class OleVariant
 #endif // FEATURE_COMINTEROP
         void (*OleToComArray)(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pInterfaceMT);
         void (*ComToOleArray)(BASEARRAYREF* pComArray, void* oleArray, MethodTable* pInterfaceMT,
-                                                       BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid);
+                                 BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, 
+                              BOOL fOleArrayIsValid,SIZE_T cElements);
         void (*ClearOleArray)(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
     };
 
@@ -464,33 +466,38 @@ private:
     static void MarshalBoolArrayOleToCom(void *oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
-                                            MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid);
+                                         MethodTable* pInterfaceMT, BOOL fBestFitMapping,
+                                         BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid,
+                                         SIZE_T cElements);
 
     static void MarshalWinBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalWinBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, 
+                                            SIZE_T cElements);
     static void MarshalCBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant);
     static void MarshalCBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant);
     static void MarshalCBoolVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant);
     static void MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
-                                            MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                          MethodTable* pInterfaceMT, BOOL fBestFitMapping,
+                                          BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                          SIZE_T cElements);
 
     static void MarshalAnsiCharArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalAnsiCharArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
 
 #ifdef FEATURE_COMINTEROP
     static void MarshalIDispatchArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
 #endif // FEATURE_COMINTEROP
 
 #ifdef FEATURE_COMINTEROP
@@ -498,7 +505,8 @@ private:
                                             MethodTable* pInterfaceMT);
     static void MarshalBSTRArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
     static void ClearBSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
 #endif // FEATURE_COMINTEROP
 
@@ -506,32 +514,38 @@ private:
                                             MethodTable* pInterfaceMT);
     static void MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
     static void ClearNonBlittableRecordArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
 
     static void MarshalLPWSTRArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalLPWSTRRArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
     static void ClearLPWSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
 
     static void MarshalLPSTRArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalLPSTRRArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
     static void ClearLPSTRArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
 
     static void MarshalDateArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalDateArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
 
     static void MarshalRecordArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pElementMT);
     static void MarshalRecordArrayComToOle(BASEARRAYREF* pComArray, void* oleArray, MethodTable* pElementMT,
-                                                                               BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                           BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, 
+                                           BOOL fOleArrayValid,
+                                           SIZE_T cElements);
     static void ClearRecordArray(void* oleArray, SIZE_T cElements, MethodTable* pElementMT);
 
 #ifdef FEATURE_COMINTEROP
@@ -540,7 +554,8 @@ private:
                                             MethodTable* pInterfaceMT);
     static void MarshalIUnknownArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
     static void ClearInterfaceArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
 
     static void MarshalBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant);
@@ -581,13 +596,15 @@ private:
                                             MethodTable* pInterfaceMT);
     static void MarshalCurrencyArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
 
     static void MarshalVariantArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
                                             MethodTable* pInterfaceMT);
     static void MarshalVariantArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
                                             MethodTable* pInterfaceMT, BOOL fBestFitMapping,
-                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid);
+                                            BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid,
+                                            SIZE_T cElements);
     static void ClearVariantArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT);
 
 #ifdef FEATURE_CLASSIC_COMINTEROP
index 370b699..cf2cada 100644 (file)
@@ -17,3 +17,4 @@ add_subdirectory(StringMarshalling/LPTSTR)
 add_subdirectory(StringMarshalling/UTF8)
 add_subdirectory(MarshalAPI/FunctionPointer)
 add_subdirectory(MarshalAPI/IUnknown)
+add_subdirectory(SizeConst)
diff --git a/src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.cs b/src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.cs
new file mode 100644 (file)
index 0000000..0497f8f
--- /dev/null
@@ -0,0 +1,165 @@
+using System;
+using System.Runtime.InteropServices;
+
+class Program
+{
+    static int Main(string[] args)
+    {
+        VerifyByValBoolArray();
+        VerifyByValArrayInStruct();
+        VerfiyByValDateArray();
+        return 100;
+    }
+    
+    static void VerifyByValBoolArray()
+    {
+        var structure1 = new StructWithBoolArray()
+        {
+            array = new bool[]
+            {
+                true,true,true,true
+            }
+        };
+
+        int size = Marshal.SizeOf(structure1);
+        IntPtr memory = Marshal.AllocHGlobal(size + sizeof(Int32));
+
+        try
+        {
+            Marshal.WriteInt32(memory, size, 0xFF);
+            Marshal.StructureToPtr(structure1, memory, false);
+
+            if (Marshal.ReadInt32(memory, size) != 0xFF)
+                throw new Exception("Marshal.StructureToPtr buffer overwritten...");
+        }
+        finally
+        {
+            Marshal.FreeHGlobal(memory);
+        }
+    }
+
+    static void VerifyByValArrayInStruct()
+    {
+        // equal
+        var structure1 = new StructWithByValArray()
+        {
+            array = new StructWithIntField[]
+            {
+                new StructWithIntField { value = 1 },
+                new StructWithIntField { value = 2 },
+                new StructWithIntField { value = 3 },
+                new StructWithIntField { value = 4 },
+                new StructWithIntField { value = 5 }
+            }
+        };
+        int size = Marshal.SizeOf(structure1);
+        IntPtr memory = Marshal.AllocHGlobal(size);
+        try
+        {
+            Marshal.StructureToPtr(structure1, memory, false);
+        }
+        finally
+        {
+            Marshal.FreeHGlobal(memory);
+        }
+
+        // underflow
+        var structure2 = new StructWithByValArray()
+        {
+            array = new StructWithIntField[]
+         {
+                new StructWithIntField { value = 1 },
+                new StructWithIntField { value = 2 },
+                new StructWithIntField { value = 3 },
+                new StructWithIntField { value = 4 }
+         }
+        };
+        bool expectedException = false;
+        size = Marshal.SizeOf(structure2);
+        memory = Marshal.AllocHGlobal(size);
+        try
+        {
+            Marshal.StructureToPtr(structure2, memory, false);
+        }
+        catch (ArgumentException)
+        {
+            expectedException = true;
+        }
+        finally
+        {
+            Marshal.FreeHGlobal(memory);
+        }
+        if (!expectedException)
+            throw new Exception("Expected ArgumentException");
+
+        // overflow
+        var structure3 = new StructWithByValArray()
+        {
+            array = new StructWithIntField[]
+         {
+                new StructWithIntField { value = 1 },
+                new StructWithIntField { value = 2 },
+                new StructWithIntField { value = 3 },
+                new StructWithIntField { value = 4 },
+                new StructWithIntField { value = 5 },
+                new StructWithIntField { value = 6 }
+         }
+        };
+
+        size = Marshal.SizeOf(structure3);
+        memory = Marshal.AllocHGlobal(size);
+        try
+        {
+            Marshal.StructureToPtr(structure3, memory, false);
+        }
+        finally
+        {
+            Marshal.FreeHGlobal(memory);
+        }
+    }
+    
+    static void VerfiyByValDateArray()
+    {
+        var structure1 = new StructWithDateArray()
+        {
+           array = new DateTime[]
+           {
+                DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now , DateTime.Now, DateTime.Now
+           }
+        };
+
+        int size = Marshal.SizeOf(structure1);
+        IntPtr memory = Marshal.AllocHGlobal(size);
+        try
+        {
+            Marshal.StructureToPtr(structure1, memory, false);
+        }
+        finally
+        {
+            Marshal.FreeHGlobal(memory);
+        }
+    }
+
+    public struct StructWithIntField
+    {
+        public int value;
+    }
+
+    public struct StructWithByValArray
+    {
+        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+        public StructWithIntField[] array;
+    }
+
+    public struct StructWithBoolArray
+    {
+        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+        public bool[] array;
+    }
+
+    public struct StructWithDateArray
+    {
+        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+        public DateTime[] array;
+    }
+}
\ No newline at end of file
diff --git a/src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.csproj b/src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/MarshalStructure.csproj
new file mode 100644 (file)
index 0000000..6146e27
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>MarshalStructure</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="*.cs" />
+    <Compile Include="..\..\common\Assertion.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="project.json" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+      <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+      <Name>CoreCLRTestLibrary</Name>
+    </ProjectReference>    
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/project.json b/src/coreclr/tests/src/Interop/MarshalAPI/MarshalStructure/project.json
new file mode 100644 (file)
index 0000000..025841e
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "dependencies": {
+    "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+    "System.Collections": "4.0.10",
+    "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+    "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+    "System.ComponentModel": "4.0.1-rc3-24117-00",
+    "System.Console": "4.0.0-rc3-24117-00",
+    "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+    "System.Globalization": "4.0.10",
+    "System.Globalization.Calendars": "4.0.0",
+    "System.IO": "4.0.10",
+    "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+    "System.IO.FileSystem.Primitives": "4.0.0",
+    "System.Linq": "4.1.0-rc3-24117-00",
+    "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+    "System.Reflection": "4.1.0-rc3-24117-00",
+    "System.Reflection.Primitives": "4.0.0",
+    "System.Runtime": "4.1.0-rc3-24117-00",
+    "System.Runtime.Extensions": "4.0.10",
+    "System.Runtime.Handles": "4.0.0",
+    "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+    "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+    "System.Text.Encoding": "4.0.10",
+    "System.Threading": "4.0.10",
+    "System.Threading.Thread": "4.0.0-rc3-24117-00",
+    "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+    "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+    "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+    "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+  },
+  "frameworks": {
+    "dnxcore50": {}
+  },
+  "runtimes": {
+    "win7-x86": {},
+    "win7-x64": {},
+    "ubuntu.14.04-x64": {},
+    "osx.10.10-x64": {},
+    "centos.7-x64": {},
+    "rhel.7-x64": {},
+    "debian.8-x64": {}
+  }
+}
diff --git a/src/coreclr/tests/src/Interop/SizeConst/CMakeLists.txt b/src/coreclr/tests/src/Interop/SizeConst/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3ec7dd3
--- /dev/null
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.6)
+project (SizeConstNative)
+set(SOURCES SizeConstNative.cpp)
+
+# add the executable
+add_library (SizeConstNative SHARED ${SOURCES})
+
+# add the install targets
+install (TARGETS SizeConstNative DESTINATION bin)
+
+
diff --git a/src/coreclr/tests/src/Interop/SizeConst/SizeConstNative.cpp b/src/coreclr/tests/src/Interop/SizeConst/SizeConstNative.cpp
new file mode 100644 (file)
index 0000000..8bb822a
--- /dev/null
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <xplatform.h>
+
+const int ARRAY_SIZE = 100;
+typedef struct { char  arr[ARRAY_SIZE]; } S_CHARByValArray;
+extern "C" DLL_EXPORT BOOL TakeByValTStr(S_CHARByValArray s, int size)
+{
+    return true;
+}
\ No newline at end of file
diff --git a/src/coreclr/tests/src/Interop/SizeConst/SizeConstTest.cs b/src/coreclr/tests/src/Interop/SizeConst/SizeConstTest.cs
new file mode 100644 (file)
index 0000000..bd081a6
--- /dev/null
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+
+[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+public struct S_CHARArray_ByValTStr
+{
+    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
+    public string arr;
+    public S_CHARArray_ByValTStr(string parr) { arr = parr; }
+}
+
+class Test
+{
+    internal const int ARRAY_SIZE = 100;
+
+    //UnmanagedType.ByValTStr
+    [DllImport("SizeConstNative",CharSet = CharSet.Ansi)]
+    static extern bool TakeByValTStr(S_CHARArray_ByValTStr s, int size);
+
+    static bool SizeConstByValTStr()
+    {
+        // always marshal managedArray.Length
+        S_CHARArray_ByValTStr s = new S_CHARArray_ByValTStr();
+        s.arr = "有个可爱";
+        TakeByValTStr(s, s.arr.Length);
+
+        // off by one byte since  sizeconst == 4 and 
+        // number of bytes == 4 . We used to write 
+        // one past the buffer before but now we truncate at 3rd byte.
+        // In order to test this the locale of the machine need to 
+        // a multibyte char set.
+        s.arr = "个个";
+        TakeByValTStr(s, s.arr.Length);
+        return true;
+    }
+
+    static int Main(string[] args)
+    {
+        SizeConstByValTStr();
+        return 100;
+    }
+}
diff --git a/src/coreclr/tests/src/Interop/SizeConst/SizeConstTest.csproj b/src/coreclr/tests/src/Interop/SizeConst/SizeConstTest.csproj
new file mode 100644 (file)
index 0000000..03806a1
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <AssemblyName>SizeConstTest</AssemblyName>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <DefineConstants>$(DefineConstants);STATIC</DefineConstants>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="SizeConstTest.cs" />
+    <Compile Include="..\common\Assertion.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="project.json" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Common\CoreCLRTestLibrary\CoreCLRTestLibrary.csproj">
+      <Project>{c8c0dc74-fac4-45b1-81fe-70c4808366e0}</Project>
+      <Name>CoreCLRTestLibrary</Name>
+    </ProjectReference>
+    <ProjectReference Include="CMakeLists.txt" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/coreclr/tests/src/Interop/SizeConst/project.json b/src/coreclr/tests/src/Interop/SizeConst/project.json
new file mode 100644 (file)
index 0000000..025841e
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "dependencies": {
+    "Microsoft.NETCore.Platforms": "1.0.1-rc3-24117-00",
+    "System.Collections": "4.0.10",
+    "System.Collections.NonGeneric": "4.0.1-rc3-24117-00",
+    "System.Collections.Specialized": "4.0.1-rc3-24117-00",
+    "System.ComponentModel": "4.0.1-rc3-24117-00",
+    "System.Console": "4.0.0-rc3-24117-00",
+    "System.Diagnostics.Process": "4.1.0-rc3-24117-00",
+    "System.Globalization": "4.0.10",
+    "System.Globalization.Calendars": "4.0.0",
+    "System.IO": "4.0.10",
+    "System.IO.FileSystem": "4.0.1-rc3-24117-00",
+    "System.IO.FileSystem.Primitives": "4.0.0",
+    "System.Linq": "4.1.0-rc3-24117-00",
+    "System.Linq.Queryable": "4.0.1-rc3-24117-00",
+    "System.Reflection": "4.1.0-rc3-24117-00",
+    "System.Reflection.Primitives": "4.0.0",
+    "System.Runtime": "4.1.0-rc3-24117-00",
+    "System.Runtime.Extensions": "4.0.10",
+    "System.Runtime.Handles": "4.0.0",
+    "System.Runtime.InteropServices": "4.1.0-rc3-24117-00",
+    "System.Runtime.Loader": "4.0.0-rc3-24117-00",
+    "System.Text.Encoding": "4.0.10",
+    "System.Threading": "4.0.10",
+    "System.Threading.Thread": "4.0.0-rc3-24117-00",
+    "System.Xml.ReaderWriter": "4.0.11-rc3-24117-00",
+    "System.Xml.XDocument": "4.0.11-rc3-24117-00",
+    "System.Xml.XmlDocument": "4.0.1-rc3-24117-00",
+    "System.Xml.XmlSerializer": "4.0.11-rc3-24117-00"
+  },
+  "frameworks": {
+    "dnxcore50": {}
+  },
+  "runtimes": {
+    "win7-x86": {},
+    "win7-x64": {},
+    "ubuntu.14.04-x64": {},
+    "osx.10.10-x64": {},
+    "centos.7-x64": {},
+    "rhel.7-x64": {},
+    "debian.8-x64": {}
+  }
+}
index 6bd83f0..4f68d71 100644 (file)
@@ -355,3 +355,4 @@ JIT/Regression/VS-ia64-JIT/V2.0-Beta2/b410474/b410474/b410474.sh
 JIT/Regression/VS-ia64-JIT/V2.0-RTM/b286991/b286991/b286991.sh
 managed/Compilation/Compilation/Compilation.sh
 Regressions/coreclr/0584/Test584/Test584.sh
+Interop/SizeConst/SizeConstTest/SizeConstTest.sh