From 5d41cb351855dd77e4918b2c94ece848e79cd88f Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 20 Apr 2018 21:57:08 -0700 Subject: [PATCH 1/2] Fix built-in GetHashCode crash on nested structs Fixes #17661 --- src/vm/comutilnative.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vm/comutilnative.cpp b/src/vm/comutilnative.cpp index b75f6849925d..75ecd59e63a1 100644 --- a/src/vm/comutilnative.cpp +++ b/src/vm/comutilnative.cpp @@ -2688,13 +2688,14 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef) } CONTRACTL_END; INT32 hashCode = 0; - INT32 *pObj = (INT32*)pObjRef; + + GCPROTECT_BEGININTERIOR(pObjRef); // While we shouln't get here directly from ValueTypeHelper::GetHashCode, if we recurse we need to // be able to handle getting the hashcode for an embedded structure whose hashcode is computed by the fast path. if (CanUseFastGetHashCodeHelper(mt)) { - return FastGetValueTypeHashCodeHelper(mt, pObjRef); + hashCode = FastGetValueTypeHashCodeHelper(mt, pObjRef); } else { @@ -2715,13 +2716,12 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef) { FieldDesc *field = fdIterator.Next(); _ASSERTE(!field->IsRVA()); - void *pFieldValue = (BYTE *)pObj + field->GetOffsetUnsafe(); + void *pFieldValue = (BYTE *)pObjRef + field->GetOffsetUnsafe(); if (field->IsObjRef()) { // if we get an object reference we get the hash code out of that if (*(Object**)pFieldValue != NULL) { - OBJECTREF fieldObjRef = ObjectToOBJECTREF(*(Object **) pFieldValue); GCPROTECT_BEGIN(fieldObjRef); @@ -2752,7 +2752,7 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef) else { // got another value type. Get the type - TypeHandle fieldTH = field->LookupFieldTypeHandle(); // the type was loaded already + TypeHandle fieldTH = field->GetFieldTypeHandleThrowing(); _ASSERTE(!fieldTH.IsNull()); hashCode = RegularGetValueTypeHashCode(fieldTH.GetMethodTable(), pValue); } @@ -2761,6 +2761,8 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef) } } } + GCPROTECT_END(); + return hashCode; } From 35bcd7465cfcf68e65ea4125a5cff9fc476d9025 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sat, 21 Apr 2018 18:25:23 -0700 Subject: [PATCH 2/2] Fix GC hole --- src/vm/comutilnative.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vm/comutilnative.cpp b/src/vm/comutilnative.cpp index 75ecd59e63a1..d838c7b68d15 100644 --- a/src/vm/comutilnative.cpp +++ b/src/vm/comutilnative.cpp @@ -2716,9 +2716,10 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef) { FieldDesc *field = fdIterator.Next(); _ASSERTE(!field->IsRVA()); - void *pFieldValue = (BYTE *)pObjRef + field->GetOffsetUnsafe(); if (field->IsObjRef()) { + void *pFieldValue = (BYTE *)pObjRef + field->GetOffsetUnsafe(); + // if we get an object reference we get the hash code out of that if (*(Object**)pFieldValue != NULL) { @@ -2741,11 +2742,11 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef) } else { - UINT fieldSize = field->LoadSize(); - INT32 *pValue = (INT32*)pFieldValue; CorElementType fieldType = field->GetFieldType(); if (fieldType != ELEMENT_TYPE_VALUETYPE) { + UINT fieldSize = field->LoadSize(); + INT32 *pValue = (INT32*)((BYTE *)pObjRef + field->GetOffsetUnsafe()); for (INT32 j = 0; j < (INT32)(fieldSize / sizeof(INT32)); j++) hashCode ^= *pValue++; } @@ -2754,7 +2755,7 @@ static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef) // got another value type. Get the type TypeHandle fieldTH = field->GetFieldTypeHandleThrowing(); _ASSERTE(!fieldTH.IsNull()); - hashCode = RegularGetValueTypeHashCode(fieldTH.GetMethodTable(), pValue); + hashCode = RegularGetValueTypeHashCode(fieldTH.GetMethodTable(), (BYTE *)pObjRef + field->GetOffsetUnsafe()); } } break;