Skip to content

Commit 634641c

Browse files
[clr-interp] Access checks and callouts (#120581)
* Add CallSiteCalloutSupport * Add access check handling for fields and other instructions * Update src/coreclr/interpreter/compiler.cpp Co-authored-by: Copilot <[email protected]> * Enhance helper methods to reduce code duplication --------- Co-authored-by: Copilot <[email protected]>
1 parent e572463 commit 634641c

File tree

5 files changed

+197
-0
lines changed

5 files changed

+197
-0
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,11 @@ static void FreeInterpreterStackMap(void *key, void *value, void *userdata)
16451645
delete (InterpreterStackMap *)value;
16461646
}
16471647

1648+
static void InterpreterCompilerBreak()
1649+
{
1650+
assert(!"InterpreterCompilerBreak reached");
1651+
}
1652+
16481653
InterpCompiler::InterpCompiler(COMP_HANDLE compHnd,
16491654
CORINFO_METHOD_INFO* methodInfo)
16501655
: m_stackmapsByClass(FreeInterpreterStackMap)
@@ -1689,6 +1694,13 @@ InterpMethod* InterpCompiler::CompileMethod()
16891694
printf("Interpreter compile method %s\n", m_methodName.GetUnderlyingArray());
16901695
}
16911696
#endif
1697+
#ifdef DEBUG
1698+
if (InterpConfig.InterpBreak().contains(m_compHnd, m_methodInfo->ftn, m_classHnd, &m_methodInfo->args))
1699+
{
1700+
InterpreterCompilerBreak();
1701+
}
1702+
#endif
1703+
16921704
m_isSynchronized = m_compHnd->getMethodAttribs(m_methodHnd) & CORINFO_FLG_SYNCH;
16931705
if (m_isSynchronized)
16941706
{
@@ -3679,6 +3691,90 @@ void InterpCompiler::EmitCalli(bool isTailCall, void* calliCookie, int callIFunc
36793691
m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, callIFunctionPointerVar);
36803692
}
36813693

3694+
void InterpCompiler::EmitCanAccessCallout(CORINFO_RESOLVED_TOKEN *pResolvedToken)
3695+
{
3696+
CORINFO_HELPER_DESC calloutHelper;
3697+
CorInfoIsAccessAllowedResult accessAllowed =
3698+
m_compHnd->canAccessClass(pResolvedToken, m_methodHnd, &calloutHelper);
3699+
3700+
// Inject call to callsite callout helper
3701+
EmitCallsiteCallout(accessAllowed, &calloutHelper);
3702+
}
3703+
3704+
void InterpCompiler::EmitCallsiteCallout(CorInfoIsAccessAllowedResult accessAllowed, CORINFO_HELPER_DESC* calloutDesc)
3705+
{
3706+
if (accessAllowed == CORINFO_ACCESS_ILLEGAL)
3707+
{
3708+
int32_t svars[CORINFO_ACCESS_ALLOWED_MAX_ARGS];
3709+
3710+
for (unsigned i = 0; i < calloutDesc->numArgs; i++)
3711+
{
3712+
void *value = NULL;
3713+
void *pValue = NULL;
3714+
3715+
switch (calloutDesc->args[i].argType)
3716+
{
3717+
case CORINFO_HELPER_ARG_TYPE_Class:
3718+
value = (void*)m_compHnd->embedClassHandle(calloutDesc->args[i].classHandle, &pValue);
3719+
break;
3720+
case CORINFO_HELPER_ARG_TYPE_Method:
3721+
value = (void*)m_compHnd->embedMethodHandle(calloutDesc->args[i].methodHandle, &pValue);
3722+
break;
3723+
default:
3724+
NO_WAY("Callsite callout with unsupported arg type");
3725+
}
3726+
3727+
if (value == NULL)
3728+
{
3729+
if (pValue == NULL)
3730+
{
3731+
NO_WAY("Callsite callout with unsupported arg type");
3732+
}
3733+
3734+
AddIns(INTOP_LDPTR);
3735+
m_pLastNewIns->data[0] = GetDataItemIndex(pValue);
3736+
PushInterpType(InterpTypeI, nullptr);
3737+
int tempVar = m_pStackPointer[-1].var;
3738+
m_pLastNewIns->SetDVar(tempVar);
3739+
3740+
// Now we generate an LDIND_I to get the actual value out of the ref
3741+
AddIns(INTOP_LDIND_I);
3742+
m_pLastNewIns->data[0] = 0;
3743+
m_pLastNewIns->SetSVar(tempVar);
3744+
m_pStackPointer--;
3745+
PushInterpType(InterpTypeI, NULL);
3746+
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
3747+
m_pStackPointer--;
3748+
svars[i] = m_pStackPointer[0].var;
3749+
}
3750+
else
3751+
{
3752+
AddIns(INTOP_LDPTR);
3753+
m_pLastNewIns->data[0] = GetDataItemIndex(value);
3754+
PushInterpType(InterpTypeI, nullptr);
3755+
svars[i] = m_pStackPointer[-1].var;
3756+
m_pLastNewIns->SetDVar(svars[i]);
3757+
m_pStackPointer--;
3758+
}
3759+
}
3760+
if (calloutDesc->numArgs == 2)
3761+
{
3762+
AddIns(INTOP_CALL_HELPER_V_SS);
3763+
m_pLastNewIns->SetSVars2(svars[0], svars[1]);
3764+
}
3765+
else if (calloutDesc->numArgs == 3)
3766+
{
3767+
AddIns(INTOP_CALL_HELPER_V_SSS);
3768+
m_pLastNewIns->SetSVars3(svars[0], svars[1], svars[2]);
3769+
}
3770+
else
3771+
{
3772+
NO_WAY("Callsite callout with unsupported number of args");
3773+
}
3774+
m_pLastNewIns->data[0] = GetDataForHelperFtn(calloutDesc->helperNum);
3775+
}
3776+
}
3777+
36823778
void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool readonly, bool tailcall, bool newObj, bool isCalli)
36833779
{
36843780
uint32_t token = getU4LittleEndian(m_ip + 1);
@@ -3761,6 +3857,10 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
37613857
flags = (CORINFO_CALLINFO_FLAGS)(flags | CORINFO_CALLINFO_CALLVIRT);
37623858

37633859
m_compHnd->getCallInfo(&resolvedCallToken, pConstrainedToken, m_methodInfo->ftn, flags, &callInfo);
3860+
3861+
// Inject call to callsite callout helper
3862+
EmitCallsiteCallout(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper);
3863+
37643864
if (callInfo.methodFlags & CORINFO_FLG_INTRINSIC)
37653865
{
37663866
NamedIntrinsic ni = GetNamedIntrinsic(m_compHnd, m_methodHnd, callInfo.hMethod);
@@ -6293,6 +6393,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
62936393
ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken);
62946394
m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_ADDRESS, &fieldInfo);
62956395

6396+
// Inject call to callsite callout helper
6397+
EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper);
6398+
62966399
bool isStatic = !!(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC);
62976400

62986401
if (isStatic)
@@ -6324,6 +6427,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
63246427
ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken);
63256428
m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo);
63266429

6430+
// Inject call to callsite callout helper
6431+
EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper);
6432+
63276433
CorInfoType fieldType = fieldInfo.fieldType;
63286434
bool isStatic = !!(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC);
63296435
InterpType interpFieldType = GetInterpType(fieldType);
@@ -6384,6 +6490,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
63846490
ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken);
63856491
m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo);
63866492

6493+
// Inject call to callsite callout helper
6494+
EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper);
6495+
63876496
CorInfoType fieldType = fieldInfo.fieldType;
63886497
bool isStatic = !!(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC);
63896498
InterpType interpFieldType = GetInterpType(fieldType);
@@ -6418,6 +6527,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
64186527
ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken);
64196528
m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_ADDRESS, &fieldInfo);
64206529

6530+
// Inject call to callsite callout helper
6531+
EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper);
6532+
64216533
EmitStaticFieldAddress(&fieldInfo, &resolvedToken);
64226534

64236535
m_ip += 5;
@@ -6431,6 +6543,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
64316543
ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken);
64326544
m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo);
64336545

6546+
// Inject call to callsite callout helper
6547+
EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper);
6548+
64346549
CorInfoType fieldType = fieldInfo.fieldType;
64356550
InterpType interpFieldType = GetInterpType(fieldType);
64366551

@@ -6454,6 +6569,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
64546569
ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken);
64556570
m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo);
64566571

6572+
// Inject call to callsite callout helper
6573+
EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper);
6574+
64576575
CorInfoType fieldType = fieldInfo.fieldType;
64586576
InterpType interpFieldType = GetInterpType(fieldType);
64596577

@@ -6584,6 +6702,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
65846702

65856703
CORINFO_RESOLVED_TOKEN resolvedToken;
65866704
ResolveToken(token, CORINFO_TOKENKIND_Class, &resolvedToken);
6705+
6706+
EmitCanAccessCallout(&resolvedToken);
6707+
65876708
CORINFO_GENERICHANDLE_RESULT embedInfo;
65886709
m_compHnd->embedGenericHandle(&resolvedToken, true, m_methodInfo->ftn, &embedInfo);
65896710
assert(embedInfo.compileTimeHandle != NULL);
@@ -6834,6 +6955,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
68346955
NO_WAY("Currently do not support LDFTN of Parameterized functions");
68356956
}
68366957

6958+
// Inject call to callsite callout helper
6959+
EmitCallsiteCallout(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper);
6960+
68376961
m_pStackPointer--;
68386962
int thisVar = m_pStackPointer[0].var;
68396963

@@ -6864,6 +6988,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
68646988
NO_WAY("Currently do not support LDFTN of Parameterized functions");
68656989
}
68666990

6991+
// Inject call to callsite callout helper
6992+
EmitCallsiteCallout(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper);
6993+
68676994
DO_LDFTN:
68686995
if (callInfo.kind == CORINFO_CALL)
68696996
{
@@ -6961,6 +7088,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
69617088
CHECK_STACK(1);
69627089
CORINFO_RESOLVED_TOKEN resolvedToken;
69637090
ResolveToken(token, CORINFO_TOKENKIND_Box, &resolvedToken);
7091+
7092+
EmitCanAccessCallout(&resolvedToken);
7093+
69647094
if (m_compHnd->isValueClass(resolvedToken.hClass))
69657095
{
69667096
CORINFO_GENERICHANDLE_RESULT embedInfo;
@@ -6980,6 +7110,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
69807110
CHECK_STACK(1);
69817111
CORINFO_RESOLVED_TOKEN resolvedToken;
69827112
ResolveToken(token, CORINFO_TOKENKIND_Class, &resolvedToken);
7113+
7114+
EmitCanAccessCallout(&resolvedToken);
7115+
69837116
CORINFO_GENERICHANDLE_RESULT embedInfo;
69847117
m_compHnd->embedGenericHandle(&resolvedToken, false, m_methodInfo->ftn, &embedInfo);
69857118
DeclarePointerIsClass((CORINFO_CLASS_HANDLE)embedInfo.compileTimeHandle);
@@ -7067,6 +7200,8 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
70677200
CORINFO_RESOLVED_TOKEN resolvedToken;
70687201
ResolveToken(token, CORINFO_TOKENKIND_Newarr, &resolvedToken);
70697202

7203+
EmitCanAccessCallout(&resolvedToken);
7204+
70707205
CORINFO_CLASS_HANDLE arrayClsHnd = resolvedToken.hClass;
70717206
CorInfoHelpFunc helpFunc = m_compHnd->getNewArrHelper(arrayClsHnd);
70727207
DeclarePointerIsClass(arrayClsHnd);
@@ -7465,6 +7600,8 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
74657600
CORINFO_RESOLVED_TOKEN resolvedToken;
74667601
ResolveToken(getU4LittleEndian(m_ip + 1), CORINFO_TOKENKIND_Casting, &resolvedToken);
74677602

7603+
EmitCanAccessCallout(&resolvedToken);
7604+
74687605
CorInfoHelpFunc castingHelper = m_compHnd->getCastingHelper(&resolvedToken, *m_ip == CEE_CASTCLASS /* throwing */);
74697606

74707607
CORINFO_GENERICHANDLE_RESULT embedInfo;

src/coreclr/interpreter/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,8 @@ class InterpCompiler
746746
void EmitBox(StackInfo* pStackInfo, const CORINFO_GENERICHANDLE_RESULT &boxType, bool argByRef);
747747
void EmitLeave(int32_t ilOffset, int32_t target);
748748
void EmitPushSyncObject();
749+
void EmitCallsiteCallout(CorInfoIsAccessAllowedResult accessAllowed, CORINFO_HELPER_DESC* calloutDesc);
750+
void EmitCanAccessCallout(CORINFO_RESOLVED_TOKEN *pResolvedToken);
749751

750752
// Var Offset allocator
751753
TArray<InterpInst*, MemPoolAllocator> *m_pActiveCalls;

src/coreclr/interpreter/inc/intops.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,10 @@ OPDEF(INTOP_CALL_HELPER_V_AGS, "call.helper.v.ags", 6, 1, 2, InterpOpGenericHelp
403403
// Call a helper function with a signature of void helper(SVar1, AddrOfSVar2)
404404
OPDEF(INTOP_CALL_HELPER_V_SA, "call.helper.v.sa", 4, 0, 2, InterpOpHelperFtnNoArgs)
405405

406+
// Call a helper function with a signature of void helper(Pointer,Pointer,Pointer)
407+
OPDEF(INTOP_CALL_HELPER_V_SS, "call.helper.v.ss", 4, 0, 2, InterpOpHelperFtnNoArgs)
408+
OPDEF(INTOP_CALL_HELPER_V_SSS, "call.helper.v.sss", 5, 0, 3, InterpOpHelperFtnNoArgs)
409+
406410
OPDEF(INTOP_GENERICLOOKUP, "generic", 4, 1, 1, InterpOpGenericLookup)
407411

408412
OPDEF(INTOP_CALL_FINALLY, "call.finally", 2, 0, 0, InterpOpBranch)

src/coreclr/interpreter/interpconfigvalues.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
RELEASE_CONFIG_METHODSET(Interpreter, "Interpreter")
2323
CONFIG_METHODSET(InterpHaltOnCall, "InterpHaltOnCall"); // Assert in the compiler when compiling a call to these method(s)
2424
CONFIG_METHODSET(InterpHalt, "InterpHalt");
25+
CONFIG_METHODSET(InterpBreak, "InterpBreak"); // Break into the debugger when compiling this method
2526
CONFIG_METHODSET(InterpDump, "InterpDump");
2627
CONFIG_INTEGER(InterpList, "InterpList", 0); // List the methods which are compiled by the interpreter JIT
2728
RELEASE_CONFIG_INTEGER(InterpMode, "InterpMode", 0); // Interpreter mode, one of the following:

src/coreclr/vm/interpexec.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2333,6 +2333,59 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
23332333
ip += 4;
23342334
break;
23352335
}
2336+
case INTOP_CALL_HELPER_V_SS:
2337+
{
2338+
void* helperArg1 = LOCAL_VAR(ip[1], void*);
2339+
void* helperArg2 = LOCAL_VAR(ip[2], void*);
2340+
MethodDesc *pILTargetMethod = NULL;
2341+
HELPER_FTN_V_PP helperFtn = GetPossiblyIndirectHelper<HELPER_FTN_V_PP>(pMethod, ip[3], &pILTargetMethod);
2342+
if (pILTargetMethod != NULL)
2343+
{
2344+
returnOffset = pMethod->allocaSize;
2345+
callArgsOffset = pMethod->allocaSize;
2346+
2347+
// Pass arguments to the target method
2348+
LOCAL_VAR(callArgsOffset, void*) = helperArg1;
2349+
LOCAL_VAR(callArgsOffset + INTERP_STACK_SLOT_SIZE, void*) = helperArg2;
2350+
2351+
targetMethod = pILTargetMethod;
2352+
ip += 4;
2353+
goto CALL_INTERP_METHOD;
2354+
}
2355+
2356+
_ASSERTE(helperFtn != NULL);
2357+
helperFtn(helperArg1, helperArg2);
2358+
ip += 4;
2359+
break;
2360+
}
2361+
2362+
case INTOP_CALL_HELPER_V_SSS:
2363+
{
2364+
void* helperArg1 = LOCAL_VAR(ip[1], void*);
2365+
void* helperArg2 = LOCAL_VAR(ip[2], void*);
2366+
void* helperArg3 = LOCAL_VAR(ip[3], void*);
2367+
MethodDesc *pILTargetMethod = NULL;
2368+
HELPER_FTN_V_PPP helperFtn = GetPossiblyIndirectHelper<HELPER_FTN_V_PPP>(pMethod, ip[4], &pILTargetMethod);
2369+
if (pILTargetMethod != NULL)
2370+
{
2371+
returnOffset = pMethod->allocaSize;
2372+
callArgsOffset = pMethod->allocaSize;
2373+
2374+
// Pass arguments to the target method
2375+
LOCAL_VAR(callArgsOffset, void*) = helperArg1;
2376+
LOCAL_VAR(callArgsOffset + INTERP_STACK_SLOT_SIZE, void*) = helperArg2;
2377+
LOCAL_VAR(callArgsOffset + 2 * INTERP_STACK_SLOT_SIZE, void*) = helperArg3;
2378+
2379+
targetMethod = pILTargetMethod;
2380+
ip += 5;
2381+
goto CALL_INTERP_METHOD;
2382+
}
2383+
2384+
_ASSERTE(helperFtn != NULL);
2385+
helperFtn(helperArg1, helperArg2, helperArg3);
2386+
ip += 5;
2387+
break;
2388+
}
23362389

23372390
case INTOP_CALLVIRT_TAIL:
23382391
case INTOP_CALLVIRT:

0 commit comments

Comments
 (0)