[clr-ios] Fix SIGSEGV in open virtual delegate dispatch with interpreter#126199
[clr-ios] Fix SIGSEGV in open virtual delegate dispatch with interpreter#126199kotlarmilos wants to merge 13 commits intodotnet:mainfrom
Conversation
|
Tagging subscribers to this area: @BrzVlad, @janvorli, @kg |
There was a problem hiding this comment.
Pull request overview
Fixes an interpreter crash on iOS when invoking compiled open virtual delegate targets, and updates AppleMobile/CoreCLR libraries test selection.
Changes:
- Handle open virtual delegates whose resolved target has no interpreter bytecode (
targetIp == NULL) by skipping the delegate argument slot and directly dispatching viaCALL_INTERP_METHOD. - Remove several AppleMobile/CoreCLR test project exclusions from
src/libraries/tests.proj.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/libraries/tests.proj | Removes previously-added AppleMobile/CoreCLR test exclusions (re-enables several Serialization test projects). |
| src/coreclr/vm/interpexec.cpp | Adds a NULL-targetIp open-virtual delegate path that avoids GetTarget() and dispatches the resolved MethodDesc directly. |
|
/azp run runtime-ioslike |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Wrap the GetTarget/NonVirtualEntry2MethodDesc block in braces so the CALL_DELEGATE_INVOKE goto can legally jump past the OBJECTREF variable initialization. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract the duplicated memmove logic for removing the delegate object from call arguments into a static ShiftDelegateCallArgs() helper. Re-add System.Runtime.Serialization.Xml.Tests exclusion (dotnet#124325). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2f8a225 to
6b0cbc0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
src/libraries/Common/tests/System/Runtime/Serialization/Utils.cs:380
AssemblyDependencyResolveris unsupported on several platforms (notably Android/iOS/tvOS/Browser). This helper now special-cases Browser + AppleMobile, but it can still attempt to construct/useAssemblyDependencyResolveron Android (and potentially WASI), which would throwPlatformNotSupportedExceptionif this helper is used there.
Consider switching these guards to PlatformDetection.IsMobile (as used in other tests) or explicitly excluding all platforms where AssemblyDependencyResolver is unsupported.
public TestAssemblyLoadContext(string name, bool isCollectible, string mainAssemblyToLoadPath = null) : base(name, isCollectible)
{
if (!PlatformDetection.IsBrowser && !PlatformDetection.IsAppleMobile)
_resolver = new AssemblyDependencyResolver(mainAssemblyToLoadPath ?? Assembly.GetExecutingAssembly().Location);
}
protected override Assembly Load(AssemblyName name)
{
if (PlatformDetection.IsBrowser || PlatformDetection.IsAppleMobile)
{
return base.Load(name);
}
string assemblyPath = _resolver.ResolveAssemblyToPath(name);
if (assemblyPath != null)
src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs
Show resolved
Hide resolved
src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix ShiftDelegateCallArgs memmove length to use totalArgsSize - firstAlignedDstOffset instead of totalArgsSize - sizeOfArgsUpto16ByteAlignment to avoid reading past actual argument data when pre-alignment size is not 16-byte aligned. - Extend INTOP_CALLDELEGATE_TAIL to carry sizeOfArgsUpto16ByteAlignment and targetArgsSize (oplength 4 -> 6) so the open virtual compiled target path works correctly for tail calls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run runtime-ioslike |
|
Azure Pipelines successfully started running 1 pipeline(s). |
src/coreclr/interpreter/compiler.cpp
Outdated
| targetArgsSize = ALIGN_UP_TO(targetArgsSize, argAlignment); | ||
| targetArgsSize += size; | ||
| } | ||
| if (!found16ByteAligned) |
There was a problem hiding this comment.
Why is this needed now that you loop over all the arguments? It seems that in case no 16 byte aligned arg was found, the sizeOfArgsUpto16ByteAlignment would already be equal to the targetArgsSize.
There was a problem hiding this comment.
Removed. When no 16-byte aligned arg is found, the loop already accumulates all sizes into sizeOfArgsUpto16ByteAlignment, so it equals targetArgsSize at the end.
| OPDEF(INTOP_CALLDELEGATE, "call.delegate", 5, 1, 1, InterpOpMethodHandle) | ||
| OPDEF(INTOP_CALLDELEGATE_TAIL, "call.delegate.tail", 4, 1, 1, InterpOpMethodHandle) | ||
| OPDEF(INTOP_CALLDELEGATE, "call.delegate", 6, 1, 1, InterpOpMethodHandle) | ||
| OPDEF(INTOP_CALLDELEGATE_TAIL, "call.delegate.tail", 6, 1, 1, InterpOpMethodHandle) |
There was a problem hiding this comment.
Why are we expanding the INTOP_CALLDELEGATE_TAIL to 6 too?
There was a problem hiding this comment.
Reverted. Tail calls do not need the size metadata. The interpreted path uses pTargetMethod->argsSize, and the compiled open virtual path now skips the delegate slot with callArgsOffset += INTERP_STACK_SLOT_SIZE, matching the interpreted tail path.
There was a problem hiding this comment.
Actually it is needed since the callArgsOffset += INTERP_STACK_SLOT_SIZE approach breaks 16-byte alignment for V128 arguments (as Vlad noted in #126199 (comment)). Both tail and non-tail paths now use ShiftDelegateCallArgs which needs the size metadata.
There was a problem hiding this comment.
I really meant to ask why the call.delegate.tail size grows by 2, I would expect it to grow by 1.
…check - Revert INTOP_CALLDELEGATE_TAIL to oplength 4; tail calls use the simpler callArgsOffset += INTERP_STACK_SLOT_SIZE approach matching the interpreted tail path. already makes sizeOfArgsUpto16ByteAlignment == targetArgsSize when no V128 arg exists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Expand INTOP_CALLDELEGATE_TAIL to oplength 6 with size metadata - Use ShiftDelegateCallArgs in interpreted tail path instead of callArgsOffset + INTERP_STACK_SLOT_SIZE which breaks 16-byte alignment - Use ShiftDelegateCallArgs unconditionally in compiled open virtual path Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/coreclr/vm/interpexec.cpp:3224
- In the open-virtual + compiled-target path, the tailcall case adjusts callArgsOffset by one slot and then jumps to CALL_INTERP_METHOD. If CALL_INTERP_METHOD ends up invoking a compiled method (targetIp == NULL), the call stub expects the argument block to follow interpreter stack alignment rules from offset 0 (including 16-byte alignment for V128). Bumping the base pointer by 8 can violate those assumptions. Consider either applying the same alignment-preserving shift for this tailcall case (which likely means carrying the size metadata on INTOP_CALLDELEGATE_TAIL too), or falling back to the normal delegate invoke/shuffle-thunk path for tail calls when the resolved target is compiled.
if ((targetMethod = NonVirtualEntry2MethodDesc(targetAddress)) != NULL)
{
// In this case targetMethod holds a pointer to the MethodDesc that will be called by using targetMethodObj as
// the this pointer. This may be the final method (in the case of instance method delegates), or it may be a
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
Fix a crash when the interpreter invokes a compiled open virtual delegate target.
When the interpreter's call delegate handler detects an open virtual delegate whose resolved target is compiled (
targetIp == NULL), the code previously fell through to a generic path that calledGetTarget()on the delegate. For open delegates,GetTarget()returns null, which corrupted the argument slot and caused a SIGSEGV.The fix adds a dedicated path for open virtual delegates with compiled targets. It uses
memmoveto shift the call arguments down by one slot (removing the delegate object) while preserving 16-byte alignment for V128 arguments, then jumps toCALL_INTERP_METHODto invoke the resolvedtargetMethoddirectly. The same shifting is applied for interpreted targets in the non-tail-call path. The alignment-preserving shift logic is extracted into aShiftDelegateCallArgs()helper to avoid duplication.Additionally, this re-enables test suites previously excluded under #124325 (except
System.Runtime.Serialization.Xml.Tests, which hits a native stack overflow unrelated to this fix).