dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.43k stars 4.76k forks source link

.NET 8 WebAssembly AOT not generating trampoline functions #97906

Open AshleighAdams opened 9 months ago

AshleighAdams commented 9 months ago

Description

When building trampoline functions to call into native code, delegates marked the the UnmanagedFunctionPointer attribute in .NET 6, and .NET 7 (tho not upon initial release) are taken into account.

Since .NET 8, natively calling into these methods once again causes mono_wasm_get_interp_to_native_trampoline() to fail, and the application to crash.

Reproduction Steps

A minimal WebGL sample that encounters the bug is located here: https://github.com/AshleighAdams/dotnet-webgl-sample/pull/6

Note, that you must AOT build the sample:

$ dotnet publish --configuration Release -p:OutputPath="$(pwd)/build" && (cd build/AppBundle/ && dotnet serve -o)

Internally, the sample is calling into emscripten's GL via Silk.NET, and in the project the following delegate can be found to get AOT to trampoline the function:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void glClearColor_t(float red, float green, float blue, float alpha);

Expected behavior

Expect .NET to trampoline the call into native code correctly

Actual behavior

Crashes with an exception:

ht@http://localhost:50621/AppBundle/_framework/dotnet.runtime.js:3:12765
Ul<@http://localhost:50621/AppBundle/_framework/dotnet.runtime.js:3:175673
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[23542]:0x4f3254
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20797]:0x42e6c7
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20720]:0x42b128
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20722]:0x42b1f5
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20723]:0x42b22b
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20407]:0x3fc3e8
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20475]:0x40bcaa
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20482]:0x40bf3a
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[16516]:0x3304c5
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[533]:0x1ffbc
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[13621]:0x2a7441
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[13637]:0x2a9960
@http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[13662]:0x2ab344
tick@http://localhost:50621/AppBundle/_framework/dotnet.native.js:8:166166
[logging.ts:119:20](https://raw.githubusercontent.com/dotnet/runtime/eddf880ac57b7f2c79a77592e3e6d24d1d02f112/src/mono/wasm/runtime/logging.ts)
    Ul logging.ts:119
    <anonymous> dotnet.native.wasm:5190228
    <anonymous> dotnet.native.wasm:4384455
    <anonymous> dotnet.native.wasm:4370728
    <anonymous> dotnet.native.wasm:4370933
    <anonymous> dotnet.native.wasm:4370987
    <anonymous> dotnet.native.wasm:4178920
    <anonymous> dotnet.native.wasm:4242602
    <anonymous> dotnet.native.wasm:4243258
    <anonymous> dotnet.native.wasm:3343557
    <anonymous> dotnet.native.wasm:131004
    <anonymous> dotnet.native.wasm:2782273
    <anonymous> dotnet.native.wasm:2791776
    <anonymous> dotnet.native.wasm:2798404
    tick dotnet.native.js:8

Regression?

Yes, it worked in .NET 6 and .NET 7

Known Workarounds

Unknown for now

Configuration

WebGL, happens when built on Linux and Windows Issue is in both Chrome and Firefox, latest versions

Other information

In .NET 7, a snippet that referenced the function pointer existed to stop it from being trimmed, I tried this again but additionally on glClearColor_t() which is getting trimmed:

Marshal.GetDelegateForFunctionPointer(new nint(1), typeof(glClearColor_t));

and I also tried adding the dynamic dependency to my trampoline class:

[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(TrampolineFuncs))]

Neither of these had any success

The previous .NET 7 regression issue is here: https://github.com/dotnet/runtime/issues/76930

ghost commented 9 months ago

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

Issue Details
### Description When building trampoline functions to call into native code, delegates marked the the `UnmanagedFunctionPointer` attribute in .NET 6, and .NET 7 (tho not upon initial release) are taken into account. Since .NET 8, natively calling into these methods once again causes `mono_wasm_get_interp_to_native_trampoline()` to fail, and the application to crash. ### Reproduction Steps A minimal WebGL sample that encounters the bug is located here: https://github.com/AshleighAdams/dotnet-webgl-sample/pull/6 Note, that you must AOT build the sample: ```sh $ dotnet publish --configuration Release -p:OutputPath="$(pwd)/build" && (cd build/AppBundle/ && dotnet serve -o) ``` Internally, the sample is calling into emscripten's GL via Silk.NET, and in the project the following delegate can be found to get AOT to trampoline the function: ``` [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void glClearColor_t(float red, float green, float blue, float alpha); ``` ### Expected behavior Expect .NET to trampoline the call into native code correctly ### Actual behavior Crashes with an exception: ``` ht@http://localhost:50621/AppBundle/_framework/dotnet.runtime.js:3:12765 Ul<@http://localhost:50621/AppBundle/_framework/dotnet.runtime.js:3:175673 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[23542]:0x4f3254 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20797]:0x42e6c7 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20720]:0x42b128 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20722]:0x42b1f5 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20723]:0x42b22b @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20407]:0x3fc3e8 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20475]:0x40bcaa @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[20482]:0x40bf3a @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[16516]:0x3304c5 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[533]:0x1ffbc @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[13621]:0x2a7441 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[13637]:0x2a9960 @http://localhost:50621/AppBundle/_framework/dotnet.native.wasm:wasm-function[13662]:0x2ab344 tick@http://localhost:50621/AppBundle/_framework/dotnet.native.js:8:166166 [logging.ts:119:20](https://raw.githubusercontent.com/dotnet/runtime/eddf880ac57b7f2c79a77592e3e6d24d1d02f112/src/mono/wasm/runtime/logging.ts) Ul logging.ts:119 dotnet.native.wasm:5190228 dotnet.native.wasm:4384455 dotnet.native.wasm:4370728 dotnet.native.wasm:4370933 dotnet.native.wasm:4370987 dotnet.native.wasm:4178920 dotnet.native.wasm:4242602 dotnet.native.wasm:4243258 dotnet.native.wasm:3343557 dotnet.native.wasm:131004 dotnet.native.wasm:2782273 dotnet.native.wasm:2791776 dotnet.native.wasm:2798404 tick dotnet.native.js:8 ``` ### Regression? Yes, it worked in .NET 6 and .NET 7 ### Known Workarounds Unknown for now ### Configuration WebGL, happens when built on Linux and Windows Issue is in both Chrome and Firefox, latest versions ### Other information In .NET 7, a snippet that referenced the function pointer existed to stop it from being trimmed, I tried this again but additionally on `glClearColor_t()` which is getting trimmed: ```cs Marshal.GetDelegateForFunctionPointer(new nint(1), typeof(glClearColor_t)); ``` and I also tried adding the dynamic dependency to my trampoline class: ```cs [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(TrampolineFuncs))] ``` Neither of these had any success The previous .NET 7 regression issue is here: https://github.com/dotnet/runtime/issues/76930
Author: AshleighAdams
Assignees: -
Labels: `arch-wasm`, `untriaged`, `area-Interop-mono`
Milestone: -
lewing commented 9 months ago

cc @vargaz @kg @steveisok

kg commented 9 months ago

Are there any warnings or related messages in the build log?

AshleighAdams commented 9 months ago

@kg Not that I can see, full build log is here: https://github.com/AshleighAdams/dotnet-webgl-sample/actions/runs/7762714845/job/21173670804

lewing commented 3 months ago

@kg what is the status of this one?

kg commented 3 months ago

@kg what is the status of this one?

I didn't have an opportunity to get to the bottom of it

AshleighAdams commented 3 months ago

This is fixed in .NET 9 preview 6

Is there anything we can do to help prevent this from regressing a third time? I know this isn't an "officially" supported part of wasm yet, but nonetheless I think it is still very important

kg commented 3 months ago

We could add a simple regression test for it. I added a small suite of P/Invoke tests to our test suite while doing my p/invoke work during .NET 9. It's not obvious to me why the glClearColor call from the original report wouldn't have gotten a trampoline, though - someone who knows our AOT infrastructure better might be able to guess.