Skip to content

[browser] throw PNSE from GetFunctionPointerForDelegate #116107

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

pavelsavara
Copy link
Member

@pavelsavara pavelsavara commented May 29, 2025

  • throw meaningful exception
  • WBT unit test

Fixes #104391
Fixes #39187

@pavelsavara pavelsavara added this to the 10.0.0 milestone May 29, 2025
@pavelsavara pavelsavara self-assigned this May 29, 2025
@Copilot Copilot AI review requested due to automatic review settings May 29, 2025 18:15
@pavelsavara pavelsavara added arch-wasm WebAssembly architecture area-Interop-mono labels May 29, 2025
@pavelsavara pavelsavara added the os-browser Browser variant of arch-wasm label May 29, 2025
Copy link
Contributor

Tagging subscribers to 'arch-wasm': @lewing
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds support for throwing a PlatformNotSupportedException when GetFunctionPointerForDelegate is called on methods without an [UnmanagedCallersOnly] attribute, and wires up end-to-end tests in the Wasm Basic Test App and build tests.

  • Introduces a null‐wrapper check in interp_create_method_pointer to produce a PNSE with a descriptive message.
  • Extends main.js and the WebAssembly test app to invoke the new scenario.
  • Adds both an in-browser unit test (MiscTests.cs) and a build‐time Xunit test.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/mono/mono/mini/interp/interp.c Checks for missing native‐to‐managed wrapper and throws PNSE
src/mono/browser/runtime/runtime.c Adds an assertion to ensure method is not null
src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js Adds “GetFunctionPointerForDelegate” case to the browser harness
src/mono/wasm/testassets/WasmBasicTestApp/App/MiscTests.cs JSExport method to call GetFunctionPointerForDelegate
src/mono/wasm/Wasm.Build.Tests/MiscTests.cs Xunit test to verify the PNSE and its message
Comments suppressed due to low confidence (2)

src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js:292

  • [nitpick] The variable name retMics is ambiguous; consider renaming it to something more descriptive (e.g., result or returnValue).
const retMics = testGetFunctionPointerForDelegate();

src/mono/mono/mini/interp/interp.c:3475

  • The variable error is not defined in this scope (the parameter is named e). This should call mono_error_set_platform_not_supported(e, msg).
mono_error_set_platform_not_supported (error, msg);

@jkotas
Copy link
Member

jkotas commented May 29, 2025

throw PNSE from GetFunctionPointerForDelegate for methods without UnmanagedCallersOnly

Should GetFunctionPointerForDelegate throw PNSE unconditionally on browser?

GetFunctionPointerForDelegate does not work on methods with UnmanagedCallersOnly either (outside browser at least). For example, the following will fail to compile with error CS8902: 'MyMethod()' is attributed with 'UnmanagedCallersOnly' and cannot be converted to a delegate type.:

using System.Runtime.InteropServices;

Marshal.GetFunctionPointerForDelegate(new Action(MyMethod));

[UnmanagedCallersOnly]
static void MyMethod()
{
}

@pavelsavara
Copy link
Member Author

Should GetFunctionPointerForDelegate throw PNSE unconditionally on browser?

Hmmm, good point.

I'm looking at mono/mono#20076 but I'm not any wiser.

@lewing do you know why we have

#ifdef HOST_WASM
if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
WrapperInfo *info = mono_marshal_get_wrapper_info (method);
MonoMethod *orig_method = info->d.native_to_managed.method;
/*
* These are called from native code. Ask the host app for a trampoline.
*/
MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
ftndesc->addr = entry_func;
ftndesc->arg = imethod;
addr = mono_wasm_get_native_to_interp_trampoline (orig_method, ftndesc);
if (addr) {
mono_memory_barrier ();
imethod->jit_entry = addr;
return addr;
}
/*
* The runtime expects a function pointer unique to method and
* the native caller expects a function pointer with the
* right signature, so fail right away.
*/
char *s = mono_method_get_full_name (orig_method);
char *msg = g_strdup_printf ("No native to managed transition for method '%s', missing [UnmanagedCallersOnly] attribute.", s);
mono_error_set_platform_not_supported (error, msg);
g_free (s);
g_free (msg);
return NULL;
}
#endif

Is this for interp->AOT transitions only ?

@pavelsavara
Copy link
Member Author

#56883 introduced the message about UnmanagedCallersOnly

@lewing
Copy link
Member

lewing commented May 29, 2025

I'd need to a few minutes to investigate to be sure, but I suspect this just a case where we are ending up in interp_create_method_pointer from different paths. We do expect a native to interp trampoline to exist for UCO methods (if the native build is enabled), that does not mean we intended GetFunctionPointerForDelegate to succeed if the attribute exists.

@jkotas
Copy link
Member

jkotas commented May 31, 2025

BTW: You can reuse message added in https://github.com/dotnet/runtime/pull/116010/files#diff-d9a9b46d55b2e1fddcd071cc75b0408f92f33befa5ea92d5b6aa0c67ad437071R4365 to make this API unsupported on wasm.

@jkotas
Copy link
Member

jkotas commented Jun 4, 2025

dotnet/dotnet-api-docs#11401 is a docs updated related to this change:

@pavelsavara pavelsavara changed the title [browser] throw PNSE from GetFunctionPointerForDelegate for methods without UnmanagedCallersOnly [browser] throw PNSE from GetFunctionPointerForDelegate Jun 4, 2025
@pavelsavara pavelsavara force-pushed the get_native_to_interp branch from 27fed36 to a25e98d Compare June 9, 2025 11:11
@@ -244,9 +244,11 @@ public void FromManaged(LdapReferralCallback managed)
{
_managed = managed;
_native.sizeofcallback = sizeof(Native);
#pragma warning disable CA1416 // This call site is reachable on all platforms.
Copy link
Member

@jkotas jkotas Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the Wasm compat check be disabled in .csproj files for libraries like Ldap instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-wasm WebAssembly architecture area-Interop-mono os-browser Browser variant of arch-wasm
Projects
None yet
4 participants