Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 161 additions & 77 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line numberDiff line numberDiff line change
Expand Up@@ -8394,7 +8394,6 @@ MethodTableBuilder::HandleExplicitLayout(
// Instance slice size is the total size of an instance, and is calculated as
// the field whose offset and size add to the greatest number.
UINT instanceSliceSize = 0;
DWORD firstObjectOverlapOffset = ((DWORD)(-1));

UINT i;
for (i = 0; i < bmtMetaData->cFields; i++)
Expand DownExpand Up@@ -8433,15 +8432,19 @@ MethodTableBuilder::HandleExplicitLayout(
//
// 1. Verify that every OREF or BYREF is on a valid alignment.
// 2. Verify that OREFs only overlap with other OREFs.
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
// 3. Verify that BYREFs only overlap with other BYREFs.
// 4. If an OREF does overlap with another OREF, the class is marked unverifiable.
// 5. If a BYREF does overlap with another BYREF, the class is marked unverifiable.
// 6. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()).
//
char emptyObject[TARGET_POINTER_SIZE];
char isObject[TARGET_POINTER_SIZE];
char isByRef[TARGET_POINTER_SIZE];
for (i = 0; i < TARGET_POINTER_SIZE; i++)
{
emptyObject[i] = empty;
isObject[i] = oref;
isByRef[i] = byref;
}

ExplicitClassTrust explicitClassTrust;
Expand DownExpand Up@@ -8482,7 +8485,7 @@ MethodTableBuilder::HandleExplicitLayout(
CorElementType type = pFD->GetFieldType();
if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type))
{
// Check that the ref offset is pointer aligned
// Check that the field is pointer aligned
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
badOffset = pFD->GetOffset_NoLogging();
Expand All@@ -8491,98 +8494,101 @@ MethodTableBuilder::HandleExplicitLayout(
// If we got here, OREF or BYREF field was not pointer aligned. THROW.
break;
}
}

if (CorTypeInfo::IsObjRef(type))
{
// check if overlaps another object
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0)
// Determine which tag type we are working with.
bmtFieldLayoutTag tag;
SIZE_T tagBlockSize;
void* tagBlock;
if (CorTypeInfo::IsObjRef(type))
{
// If we got here, an OREF overlapped another OREF. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);

if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging();
}
tagBlockSize = sizeof(isObject);
tagBlock = (void*)isObject;
tag = oref;
}
else
{
_ASSERTE(CorTypeInfo::IsByRef(type));
tagBlockSize = sizeof(isByRef);
tagBlock = (void*)isByRef;
tag = byref;
}

// Check if there is overlap with its own tag type
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tagBlock, tagBlockSize) == 0)
{
// If we got here, there is tag type overlap. We permit this but mark the class unverifiable.
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
continue;
}
// check if is empty at this point
// check if typed layout is empty at this point
if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)emptyObject, sizeof(emptyObject)) == 0)
{
// If we got here, this OREF is overlapping no other fields (yet). Record that these bytes now contain an OREF.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, sizeof(isObject));
// If we got here, this tag type is overlapping no other fields (yet).
// Record that these bytes now contain the current tag type.
memset((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], tag, tagBlockSize);
fieldTrust.SetTrust(ExplicitFieldTrust::kNonOverLayed);
continue;
}

// If we got here, the OREF overlaps a non-OREF. THROW.
// If we got here, the tag overlaps something else. THROW.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
else
{
UINT fieldSize;
if (pFD->IsByValue())
if (!pFD->IsByValue())
{
fieldSize = GetFieldSize(pFD);
}
else
{
MethodTable *pByValueMT = pByValueClassCache[valueClassCacheIndex];
if (pByValueMT->IsByRefLike())
if (pByValueMT->IsByRefLike() || pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0)
{
// If we got here, then a byref-like valuetype was misaligned.
// If we got here, then a ByRefLike valuetype or a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
}
if (pByValueMT->ContainsPointers())
{
if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) == 0)
{
ExplicitFieldTrust::TrustLevel trust;
DWORD firstObjectOverlapOffsetInsideValueClass = ((DWORD)(-1));
trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()], &firstObjectOverlapOffsetInsideValueClass);
fieldTrust.SetTrust(trust);
if (firstObjectOverlapOffsetInsideValueClass != ((DWORD)(-1)))
{
if (firstObjectOverlapOffset == ((DWORD)(-1)))
{
firstObjectOverlapOffset = pFD->GetOffset_NoLogging() + firstObjectOverlapOffsetInsideValueClass;
}
}

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
ExplicitFieldTrust::TrustLevel trust = CheckValueClassLayout(pByValueMT, &pFieldLayout[pFD->GetOffset_NoLogging()]);
fieldTrust.SetTrust(trust);

if (trust != ExplicitFieldTrust::kNone)
{
continue;
}
else
{
// If we got here, then an OREF/BYREF inside the valuetype illegally overlapped a non-OREF field. THROW.
badOffset = pFD->GetOffset_NoLogging();
break;
}
// If we got here, then a valuetype containing an OREF was misaligned.
badOffset = pFD->GetOffset_NoLogging();
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
}
// no pointers so fall through to do standard checking
fieldSize = pByValueMT->GetNumInstanceFieldBytes();
}
else

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs or byrefs under this field
BYTE *loc = NULL;
BYTE* currOffset = pFieldLayout + pFD->GetOffset_NoLogging();
BYTE* endOffset = currOffset + fieldSize;
for (; currOffset < endOffset; ++currOffset)
{
// field size temporarily stored in pInterface field
fieldSize = GetFieldSize(pFD);
if (*currOffset == oref || *currOffset == byref)
{
loc = currOffset;
break;
}
}

// If we got here, we are trying to place a non-OREF (or a valuetype composed of non-OREFs.)
// Look for any orefs under this field
BYTE *loc;
if ((loc = (BYTE*)memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], oref, fieldSize)) == NULL)
if (loc == NULL)
{
// If we have a nonoref in the range then we are doing an overlay
if(memchr((void*)&pFieldLayout[pFD->GetOffset_NoLogging()], nonoref, fieldSize))
Expand All@@ -8598,7 +8604,7 @@ MethodTableBuilder::HandleExplicitLayout(
}

// If we got here, we tried to place a non-OREF (or a valuetype composed of non-OREFs)
// on top of an OREF. THROW.
// on top of an OREF/BYREF. THROW.
badOffset = (UINT)(loc - pFieldLayout);
fieldTrust.SetTrust(ExplicitFieldTrust::kNone);
break;
Expand DownExpand Up@@ -8716,27 +8722,29 @@ MethodTableBuilder::HandleExplicitLayout(
} // MethodTableBuilder::HandleExplicitLayout

//*******************************************************************************
// make sure that no object fields are overlapped incorrectly, returns S_FALSE if
// there overlap but nothing illegal, S_OK if there is no overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout, DWORD *pFirstObjectOverlapOffset)
// make sure that no object fields are overlapped incorrectly, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;

// ByRefLike types need to be checked for ByRef fields.
if (pMT->IsByRefLike())
return CheckByRefLikeValueClassLayout(pMT, pFieldLayout);

*pFirstObjectOverlapOffset = (DWORD)(-1);
// This method assumes there is a GC desc associated with the MethodTable.
_ASSERTE(pMT->ContainsPointers());

// Build a layout of the value class. Don't know the sizes of all the fields easily, but
// do know a) vc is already consistent so don't need to check it's overlaps and
// b) size and location of all objectrefs. So build it by setting all non-oref
// Build a layout of the value class (vc). Don't know the sizes of all the fields easily, but
// do know (a) vc is already consistent so don't need to check it's overlaps and
// (b) size and location of all objectrefs. So build it by setting all non-oref
// then fill in the orefs later
UINT fieldSize = pMT->GetNumInstanceFieldBytes();

CQuickBytes qb;
BYTE *vcLayout = (BYTE*) qb.AllocThrows(fieldSize * sizeof(BYTE));

memset((void*)vcLayout, nonoref, fieldSize);

// use pointer series to locate the orefs

CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
CGCDescSeries *pSeries = map->GetLowestSeries();

Expand All@@ -8748,11 +8756,9 @@ MethodTableBuilder::HandleExplicitLayout(
pSeries++;
}


ExplicitClassTrust explicitClassTrust;

for (UINT i=0; i < fieldSize; i++) {

for (UINT i=0; i < fieldSize; i++)
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);

if (vcLayout[i] == oref) {
Expand All@@ -8771,10 +8777,6 @@ MethodTableBuilder::HandleExplicitLayout(
// oref <--> oref
case oref:
fieldTrust.SetTrust(ExplicitFieldTrust::kLegal);
if ((*pFirstObjectOverlapOffset) == ((DWORD)(-1)))
{
*pFirstObjectOverlapOffset = (DWORD)i;
}
break;

default:
Expand DownExpand Up@@ -8810,10 +8812,92 @@ MethodTableBuilder::HandleExplicitLayout(
}


//*******************************************************************************
// make sure that no byref/object fields are overlapped, returns the trust level
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::CheckByRefLikeValueClassLayout(MethodTable * pMT, BYTE *pFieldLayout)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMT->IsByRefLike());

// ByReference<T> is an indication for a byref field, treat it as such.
if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref);

ExplicitClassTrust explicitClassTrust;

ExplicitFieldTrust::TrustLevel trust;
ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
{
ExplicitFieldTrustHolder fieldTrust(&explicitClassTrust);
int fieldStartIndex = pFD->GetOffset();

if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
MethodTable *pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
trust = CheckValueClassLayout(pFieldMT, &pFieldLayout[fieldStartIndex]);
}
else if (pFD->IsObjRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, oref);
}
else if (pFD->IsByRef())
{
_ASSERTE(fieldStartIndex % TARGET_POINTER_SIZE == 0);
trust = MarkTagType(&pFieldLayout[fieldStartIndex], TARGET_POINTER_SIZE, byref);
}
else
{
trust = MarkTagType(&pFieldLayout[fieldStartIndex], pFD->GetSize(), nonoref);
}

fieldTrust.SetTrust(trust);

// Some invalid overlap was detected.
if (trust == ExplicitFieldTrust::kNone)
break;
}

return explicitClassTrust.GetTrustLevel();
}

//*******************************************************************************
// Set the field's tag type and/or detect invalid overlap
/*static*/ ExplicitFieldTrust::TrustLevel MethodTableBuilder::MarkTagType(BYTE* field, SIZE_T fieldSize, bmtFieldLayoutTag tagType)
{
STANDARD_VM_CONTRACT;
_ASSERTE(field != NULL);
_ASSERTE(fieldSize != 0);
_ASSERTE(tagType != empty);

ExplicitFieldTrust::TrustLevel trust = ExplicitFieldTrust::kMaxTrust;
for (SIZE_T i = 0; i < fieldSize; ++i)
{
if (field[i] == empty)
{
// Nothing set for overlap, mark as requested.
field[i] = tagType;
}
else if (field[i] == tagType)
{
// Only a overlapped nonoref tag is verifiable, all others are simply legal.
ExplicitFieldTrust::TrustLevel overlapTrust = tagType == nonoref ? ExplicitFieldTrust::kVerifiable : ExplicitFieldTrust::kLegal;

// The ExplicitFieldTrust enum is ranked in descending order of trust.
// We always take the computed minimum trust level.
trust = min(trust, overlapTrust);
}
else
{
// A non-equal overlap was detected. There is no trust for the type.
trust = ExplicitFieldTrust::kNone;
break;
}
}

return trust;
}

//*******************************************************************************
void MethodTableBuilder::FindPointerSeriesExplicit(UINT instanceSliceSize,
Expand Down
14 changes: 11 additions & 3 deletions src/coreclr/vm/methodtablebuilder.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -2089,7 +2089,7 @@ class MethodTableBuilder

// --------------------------------------------------------------------------------------------
// Used for analyzing overlapped fields defined by explicit layout types.
enum bmtFieldLayoutTag {empty, nonoref, oref};
enum bmtFieldLayoutTag {empty, nonoref, oref, byref};

// --------------------------------------------------------------------------------------------
// used for calculating pointer series for tdexplicit
Expand DownExpand Up@@ -2932,8 +2932,16 @@ class MethodTableBuilder

static ExplicitFieldTrust::TrustLevel CheckValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout,
DWORD * pFirstObjectOverlapOffset);
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel CheckByRefLikeValueClassLayout(
MethodTable * pMT,
BYTE * pFieldLayout);

static ExplicitFieldTrust::TrustLevel MarkTagType(
BYTE* field,
SIZE_T size,
bmtFieldLayoutTag tagType);

void FindPointerSeriesExplicit(
UINT instanceSliceSize,
Expand Down
Loading