Skip to content

Commit 7baffba

Browse files
janvorliCopilot
andauthored
Fix interpreter delegate calls with large alignment of first arg (#121936)
There is a problem with delegate calls when the first target arch is aligned to 16 bytes. One path to call the delegate removes the delegate obj from the argument list by moving the arguments on the interpreter stack by the size of the delegate obj slot. But in the problematic case, the stack slot of the delegate obj is followed by an unused slot that ensures the alignment of the first target argument that starts after it. Moving the arguments by the 8 bytes garbles the arguments and makes that unused slot part of the first target arg. Moreover, it also doesn't move the last 8 bytes of the last argument due to this. This change fixes it by ensuring that we move the arguments starting at the aligned location of the first target argument. This fixes a large number of the libraries tests. --------- Co-authored-by: Copilot <[email protected]>
1 parent e2005d1 commit 7baffba

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

src/coreclr/interpreter/compiler.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4526,6 +4526,18 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
45264526
((lookup.accessType == IAT_PVALUE) ? (int32_t)PInvokeCallFlags::Indirect : 0) |
45274527
(suppressGCTransition ? (int32_t)PInvokeCallFlags::SuppressGCTransition : 0);
45284528
}
4529+
else if (opcode == INTOP_CALLDELEGATE)
4530+
{
4531+
int32_t firstTargetArgOffset = INTERP_STACK_SLOT_SIZE;
4532+
if (numArgs > 1)
4533+
{
4534+
// The first argument is the delegate obj, the second is the first target arg
4535+
// The offset of the first target arg relative to the start of delegate call args is equal to the alignment of the
4536+
// first target arg.
4537+
GetInterpTypeStackSize(m_pVars[callArgs[1]].clsHnd, m_pVars[callArgs[1]].interpType, &firstTargetArgOffset);
4538+
}
4539+
m_pLastNewIns->data[1] = firstTargetArgOffset;
4540+
}
45294541
}
45304542
break;
45314543

src/coreclr/interpreter/inc/intops.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ OPDEF(INTOP_LDFLDA, "ldflda", 4, 1, 1, InterpOpInt)
370370
// Calls
371371
OPDEF(INTOP_CALL, "call", 4, 1, 1, InterpOpMethodHandle)
372372
OPDEF(INTOP_CALL_NULLCHECK, "call.nullcheck", 4, 1, 1, InterpOpMethodHandle)
373-
OPDEF(INTOP_CALLDELEGATE, "call.delegate", 4, 1, 1, InterpOpMethodHandle)
373+
OPDEF(INTOP_CALLDELEGATE, "call.delegate", 5, 1, 1, InterpOpMethodHandle)
374374
OPDEF(INTOP_CALLDELEGATE_TAIL, "call.delegate.tail", 4, 1, 1, InterpOpMethodHandle)
375375
OPDEF(INTOP_CALLI, "calli", 6, 1, 2, InterpOpLdPtr)
376376
OPDEF(INTOP_CALLVIRT, "callvirt", 4, 1, 1, InterpOpMethodHandle)

src/coreclr/vm/interpexec.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2563,7 +2563,17 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
25632563

25642564
int8_t* returnValueAddress = LOCAL_VAR_ADDR(returnOffset, int8_t);
25652565

2566-
ip += 4;
2566+
// Used only for INTOP_CALLDELEGATE to allow removal of the delegate object from the argument list
2567+
size_t firstTargetArgOffset = 0;
2568+
if (*ip == INTOP_CALLDELEGATE)
2569+
{
2570+
firstTargetArgOffset = (size_t)ip[4];
2571+
ip += 5;
2572+
}
2573+
else
2574+
{
2575+
ip += 4;
2576+
}
25672577

25682578
DELEGATEREF* delegateObj = LOCAL_VAR_ADDR(callArgsOffset, DELEGATEREF);
25692579
NULL_CHECK(*delegateObj);
@@ -2624,7 +2634,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
26242634
else
26252635
{
26262636
// Shift args down by one slot to remove the delegate obj pointer
2627-
memmove(LOCAL_VAR_ADDR(callArgsOffset, int8_t), LOCAL_VAR_ADDR(callArgsOffset + INTERP_STACK_SLOT_SIZE, int8_t), pTargetMethod->argsSize);
2637+
memmove(LOCAL_VAR_ADDR(callArgsOffset, int8_t), LOCAL_VAR_ADDR(callArgsOffset + firstTargetArgOffset, int8_t), pTargetMethod->argsSize);
26282638
// Allocate child frame.
26292639
InterpMethodContextFrame *pChildFrame = pFrame->pNext;
26302640
if (!pChildFrame)

0 commit comments

Comments
 (0)