Skip to content
Merged
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
139 changes: 68 additions & 71 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2751,15 +2751,7 @@ MethodTableBuilder::EnumerateClassMethods()
BuildMethodTableThrowException(IDS_CLASSLOAD_BADFORMAT);
}

// Signature validation
if (!bmtProp->fNoSanityChecks)
{
hr = validateTokenSig(tok,pMemberSignature,cMemberSignature,dwMemberAttrs,pMDInternalImport);
if (FAILED(hr))
{
BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
}
}
bool isVtblGap = false;
if (IsMdRTSpecialName(dwMemberAttrs) || IsMdVirtual(dwMemberAttrs) || IsDelegate())
{
if (FAILED(pMDInternalImport->GetNameOfMethodDef(tok, (LPCSTR *)&strMethodName)))
Expand All @@ -2770,12 +2762,24 @@ MethodTableBuilder::EnumerateClassMethods()
{
BuildMethodTableThrowException(BFA_METHOD_NAME_TOO_LONG);
}

isVtblGap = IsMdRTSpecialName(dwMemberAttrs) && strncmp(strMethodName, "_VtblGap", 8) == 0;
}
else
{
strMethodName = NULL;
}

// Signature validation
if (!bmtProp->fNoSanityChecks && !isVtblGap)
{
hr = validateTokenSig(tok,pMemberSignature,cMemberSignature,dwMemberAttrs,pMDInternalImport);
if (FAILED(hr))
{
BuildMethodTableThrowException(hr, BFA_BAD_SIGNATURE, mdMethodDefNil);
}
}

DWORD numGenericMethodArgs = 0;

{
Expand Down Expand Up @@ -2847,85 +2851,78 @@ MethodTableBuilder::EnumerateClassMethods()
// single empty slot).
//

if (IsMdRTSpecialName(dwMemberAttrs))
if (isVtblGap)
{
PREFIX_ASSUME(strMethodName != NULL); // if we've gotten here we've called GetNameOfMethodDef

// The slot is special, but it might not be a vtable spacer. To
// determine that we must look at the name.
if (strncmp(strMethodName, "_VtblGap", 8) == 0)
{
//
// This slot doesn't really exist, don't add it to the method
// table. Instead it represents one or more empty slots, encoded
// in the method name. Locate the beginning of the count in the
// name. There are these points to consider:
// There may be no count present at all (in which case the
// count is taken as one).
// There may be an additional count just after Gap but before
// the '_'. We ignore this.
//
//
// This slot doesn't really exist, don't add it to the method
// table. Instead it represents one or more empty slots, encoded
// in the method name. Locate the beginning of the count in the
// name. There are these points to consider:
// There may be no count present at all (in which case the
// count is taken as one).
// There may be an additional count just after Gap but before
// the '_'. We ignore this.
//

LPCSTR pos = strMethodName + 8;
LPCSTR pos = strMethodName + 8;

// Skip optional number.
while (IS_DIGIT(*pos))
pos++;
// Skip optional number.
while (IS_DIGIT(*pos))
pos++;

WORD n = 0;
WORD n = 0;

// Check for presence of count.
if (*pos == '\0')
n = 1;
else
// Check for presence of count.
if (*pos == '\0')
{
n = 1;
}
else
{
if (*pos != '_')
{
if (*pos != '_')
{
BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
IDS_CLASSLOAD_BADSPECIALMETHOD,
tok);
}
BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
IDS_CLASSLOAD_BADSPECIALMETHOD,
tok);
}

// Skip '_'.
pos++;
// Skip '_'.
pos++;

// Read count.
bool fReadAtLeastOneDigit = false;
while (IS_DIGIT(*pos))
{
_ASSERTE(n < 6552);
n *= 10;
n += DIGIT_TO_INT(*pos);
pos++;
fReadAtLeastOneDigit = true;
}
// Read count.
bool fReadAtLeastOneDigit = false;
while (IS_DIGIT(*pos))
{
_ASSERTE(n < 6552);
n *= 10;
n += DIGIT_TO_INT(*pos);
pos++;
fReadAtLeastOneDigit = true;
}

// Check for end of name.
if (*pos != '\0' || !fReadAtLeastOneDigit)
{
BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
IDS_CLASSLOAD_BADSPECIALMETHOD,
tok);
}
// Check for end of name.
if (*pos != '\0' || !fReadAtLeastOneDigit)
{
BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT,
IDS_CLASSLOAD_BADSPECIALMETHOD,
tok);
}
}

#ifdef FEATURE_COMINTEROP
// Record vtable gap in mapping list. The map is an optional field, so ensure we've allocated
// these fields first.
EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
if (GetHalfBakedClass()->GetSparseCOMInteropVTableMap() == NULL)
GetHalfBakedClass()->SetSparseCOMInteropVTableMap(new SparseVTableMap());
// Record vtable gap in mapping list. The map is an optional field, so ensure we've allocated
// these fields first.
EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, GetLoaderAllocator()->GetLowFrequencyHeap());
if (GetHalfBakedClass()->GetSparseCOMInteropVTableMap() == NULL)
GetHalfBakedClass()->SetSparseCOMInteropVTableMap(new SparseVTableMap());

GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->RecordGap((WORD)NumDeclaredMethods(), n);
GetHalfBakedClass()->GetSparseCOMInteropVTableMap()->RecordGap((WORD)NumDeclaredMethods(), n);

bmtProp->fSparse = true;
bmtProp->fSparse = true;
#endif // FEATURE_COMINTEROP
continue;
}

continue;
}


//
// This is a real method so add it to the enumeration of methods. We now need to retrieve
// information on the method and store it for later use.
Expand Down