Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't validate signature for _VTblGap* methods #55616

Merged
merged 1 commit into from
Jul 14, 2021
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