Skip to content

Commit

Permalink
Fix use-out-of-scope in signature comparison (#88928)
Browse files Browse the repository at this point in the history
* Propagate token list to callers by copying instead of passing an out-of-scope address

* Create a temp token list when we create a temp compare state.

* Update the default constructor of CompareState to set a more useful empty state that won't segfault.

* Revert "Update the default constructor of CompareState to set a more useful empty state that won't segfault."

This reverts commit 28b3fd5.

* Fix last case of using the default constructor in prestub.cpp
  • Loading branch information
jkoritzinsky committed Jul 15, 2023
1 parent 0a587ff commit 2d1d727
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 14 deletions.
3 changes: 2 additions & 1 deletion src/coreclr/vm/prestub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,8 @@ namespace
continue;

// Check signature
MetaSig::CompareState state{};
TokenPairList list { nullptr };
MetaSig::CompareState state{ &list };
state.IgnoreCustomModifiers = ignoreCustomModifiers;
if (!DoesMethodMatchUnsafeAccessorDeclaration(cxt, curr, state))
continue;
Expand Down
28 changes: 17 additions & 11 deletions src/coreclr/vm/siginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3662,7 +3662,8 @@ MetaSig::CompareElementType(
}
CONTRACTL_END

CompareState temp{};
TokenPairList tempList { nullptr };
CompareState temp{ &tempList };
if (state == NULL)
state = &temp;

Expand Down Expand Up @@ -3967,7 +3968,7 @@ MetaSig::CompareElementType(
argCnt1++;

TokenPairList newVisited = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(state->Visited);
state->Visited = &newVisited;
*state->Visited = newVisited;

// Compare all parameters, incl. return parameter
while (argCnt1 > 0)
Expand Down Expand Up @@ -3998,7 +3999,7 @@ MetaSig::CompareElementType(
pSig1 - 1,
(DWORD)(pEndSig1 - pSig1) + 1);
TokenPairList newVisitedAlwaysForbidden = TokenPairList::AdjustForTypeEquivalenceForbiddenScope(state->Visited);
state->Visited = &newVisitedAlwaysForbidden;
*state->Visited = newVisitedAlwaysForbidden;

// Type constructors - The actual type is never permitted to participate in type equivalence.
if (!CompareElementType(
Expand All @@ -4024,7 +4025,7 @@ MetaSig::CompareElementType(
return FALSE;
}

state->Visited = &newVisited;
*state->Visited = newVisited;
while (argCnt1 > 0)
{
if (!CompareElementType(
Expand Down Expand Up @@ -4203,7 +4204,8 @@ MetaSig::CompareTypeDefsUnderSubstitutions(
SigPointer inst1 = pSubst1->GetInst();
SigPointer inst2 = pSubst2->GetInst();

CompareState state{ pVisited };
TokenPairList visited { pVisited };
CompareState state{ &visited };
for (DWORD i = 0; i < pTypeDef1->GetNumGenericArgs(); i++)
{
PCCOR_SIGNATURE startInst1 = inst1.GetPtr();
Expand Down Expand Up @@ -4409,6 +4411,8 @@ MetaSig::CompareMethodSigs(
IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &ArgCount1));
IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &ArgCount2));

TokenPairList visited{ pVisited };

if (ArgCount1 != ArgCount2)
{
if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_VARARG)
Expand All @@ -4430,7 +4434,7 @@ MetaSig::CompareMethodSigs(
// to correctly handle overloads, where there are a number of varargs methods
// to pick from, like m1(int,...) and m2(int,int,...), etc.

CompareState state{ pVisited };
CompareState state{ &visited };
// <= because we want to include a check of the return value!
for (i = 0; i <= ArgCount1; i++)
{
Expand Down Expand Up @@ -4486,7 +4490,7 @@ MetaSig::CompareMethodSigs(
}

// do return type as well
CompareState state{ pVisited };
CompareState state{ &visited };
for (i = 0; i <= ArgCount1; i++)
{
if (i == 0 && skipReturnTypeSig)
Expand Down Expand Up @@ -4551,7 +4555,8 @@ BOOL MetaSig::CompareFieldSigs(
pEndSig1 = pSig1 + cSig1;
pEndSig2 = pSig2 + cSig2;

CompareState state{ pVisited };
TokenPairList visited { pVisited };
CompareState state{ &visited };
return(CompareElementType(++pSig1, ++pSig2, pEndSig1, pEndSig2, pModule1, pModule2, NULL, NULL, &state));
}

Expand Down Expand Up @@ -4865,11 +4870,12 @@ BOOL MetaSig::CompareVariableConstraints(const Substitution *pSubst1,
// because they
// a) are vacuous, and
// b) may be implicit (ie. absent) in the overridden variable's declaration
TokenPairList newVisited { nullptr };
if (!(CompareTypeDefOrRefOrSpec(pModule1, tkConstraintType1, NULL,
CoreLibBinder::GetModule(), g_pObjectClass->GetCl(), NULL, NULL) ||
CoreLibBinder::GetModule(), g_pObjectClass->GetCl(), NULL, &newVisited) ||
(((specialConstraints1 & gpNotNullableValueTypeConstraint) != 0) &&
(CompareTypeDefOrRefOrSpec(pModule1, tkConstraintType1, NULL,
CoreLibBinder::GetModule(), g_pValueTypeClass->GetCl(), NULL, NULL)))))
CoreLibBinder::GetModule(), g_pValueTypeClass->GetCl(), NULL, &newVisited)))))
{
HENUMInternalHolder hEnum2(pInternalImport2);
mdGenericParamConstraint tkConstraint2;
Expand All @@ -4882,7 +4888,7 @@ BOOL MetaSig::CompareVariableConstraints(const Substitution *pSubst1,
IfFailThrow(pInternalImport2->GetGenericParamConstraintProps(tkConstraint2, &tkParam2, &tkConstraintType2));
_ASSERTE(tkParam2 == tok2);

found = CompareTypeDefOrRefOrSpec(pModule1, tkConstraintType1, pSubst1, pModule2, tkConstraintType2, pSubst2, NULL);
found = CompareTypeDefOrRefOrSpec(pModule1, tkConstraintType1, pSubst1, pModule2, tkConstraintType2, pSubst2, &newVisited);
}
if (!found)
{
Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/vm/siginfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,10 @@ class Substitution
// infinite recursion when types refer to each other in a cycle, e.g. a delegate that takes itself as
// a parameter or a struct that declares a field of itself (illegal but we don't know at this point).
//
class TokenPairList
class TokenPairList final
{
public:

// Chain using this constructor when comparing two typedefs for equivalence.
TokenPairList(mdToken token1, ModuleBase *pModule1, mdToken token2, ModuleBase *pModule2, TokenPairList *pNext)
: m_token1(token1), m_token2(token2),
Expand Down Expand Up @@ -470,7 +471,6 @@ class TokenPairList
static TokenPairList AdjustForTypeSpec(TokenPairList *pTemplate, ModuleBase *pTypeSpecModule, PCCOR_SIGNATURE pTypeSpecSig, DWORD cbTypeSpecSig);
static TokenPairList AdjustForTypeEquivalenceForbiddenScope(TokenPairList *pTemplate);

private:
TokenPairList(TokenPairList *pTemplate)
: m_token1(pTemplate ? pTemplate->m_token1 : mdTokenNil),
m_token2(pTemplate ? pTemplate->m_token2 : mdTokenNil),
Expand All @@ -480,6 +480,7 @@ class TokenPairList
m_pNext(pTemplate ? pTemplate->m_pNext : NULL)
{ LIMITED_METHOD_CONTRACT; }

private:
mdToken m_token1, m_token2;
ModuleBase *m_pModule1, *m_pModule2;
BOOL m_bInTypeEquivalenceForbiddenScope;
Expand Down

0 comments on commit 2d1d727

Please sign in to comment.