-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
[mono] inflate function pointer types; hang indirect call wrappers on the <Module> #106837
Conversation
… the <Module> 1. We were missing a case for `MONO_TYPE_FNPTR` in `inflate_generic_type` 2. When an indirect call was inside of a method that was part of a generic class, we were creating wrapper methods for the indirect calls parented by the GTD type of the caller. This ended up making common_call_trampoline consider the wrapper as needing an mrgctx. But if the caller was actually a normal closed instance type no mrgctx is set up. So we end up dereferencing a null pointer. Instead, when we create an indirect call wrapper method (which we asserted has no type params and which is always just sets up the GC transition and forwards the arguments to the indirect callee - so it never depends on the generic context), make its parent be the <Module> class of the calling assembly. This is consistent with how we cache these indirect methods (in the calling image, by the signature of the indirect callee) - it has nothing to do with the caller class. Fixes dotnet#106811
Update added. Need a testcase, I think. Here's a self-contained repro: using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace HelloWorld
{
public static class InteropUtil
{
[UnmanagedCallersOnly]
private static void Bar(int x) => Console.WriteLine ($"Bar {x}");
//[DllImport("libnative.dylib")]
public unsafe static /*extern*/ IntPtr getNativeFunctionPointer() => (IntPtr)(void*)(delegate* unmanaged<int,void>)&InteropUtil.Bar;
}
unsafe public class NativeInvoker<T>
{
[MethodImpl(MethodImplOptions.NoInlining)]
T Foo(T x) => x;
public void Invoke(IntPtr fptr, T arg)
{
T x = Foo(arg);
var func = (delegate* unmanaged<T, void>)fptr;
func(x);
}
}
internal class Program
{
private static void Main(string[] args)
{
var invoker = new NativeInvoker<int>();
invoker.Invoke(InteropUtil.getNativeFunctionPointer(), 42);
}
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks correct, not certain about the nuances though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into that!
if the cmods changed, but the sig didn't we want to return `type`. return NULL only if there's an error or if nothing else changed
should this consider merge to release/9.0? |
/backport to release/9.0 |
Started backporting to release/9.0: https://github.com/dotnet/runtime/actions/runs/10539085367 |
/backport to release/8.0-staging |
Started backporting to release/8.0-staging: https://github.com/dotnet/runtime/actions/runs/10568262373 |
@lambdageek backporting to release/8.0-staging failed, the patch most likely resulted in conflicts: $ git am --3way --ignore-whitespace --keep-non-patch changes.patch
Applying: [mono] inflate function pointer types; hang indirect call wrappers on the <Module>
Applying: pay attention to `changed` when inflating
Applying: add regression test
Using index info to reconstruct a base tree...
A src/tests/Interop/MarshalAPI/FunctionPointer/GenericFunctionPointer.cs
Falling back to patching base and 3-way merge...
CONFLICT (modify/delete): src/tests/Interop/MarshalAPI/FunctionPointer/GenericFunctionPointer.cs deleted in HEAD and modified in add regression test. Version add regression test of src/tests/Interop/MarshalAPI/FunctionPointer/GenericFunctionPointer.cs left in tree.
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Patch failed at 0003 add regression test
Error: The process '/usr/bin/git' failed with exit code 128 Please backport manually! |
@lambdageek an error occurred while backporting to release/8.0-staging, please check the run log for details! Error: git am failed, most likely due to a merge conflict. |
We were missing a case for
MONO_TYPE_FNPTR
ininflate_generic_type
When an indirect call was inside of a method that was part of a generic class, we were creating wrapper methods for the indirect calls parented by the GTD type of the caller. This ended up making common_call_trampoline consider the wrapper as needing an mrgctx. But if the caller was actually a normal closed instance type no mrgctx is set up. So we end up dereferencing a null pointer. Instead, when we create an indirect call wrapper method (which we asserted has no type params and which is always just sets up the GC transition and forwards the arguments to the indirect callee - so it never depends on the generic context), make its parent be the class of the calling assembly. This is consistent with how we cache these indirect methods (in the calling image, by the signature of the indirect callee) - it has nothing to do with the caller class.
Fixes #106811