Open drasticactions opened 1 month ago
Tagging subscribers to 'arch-wasm': @lewing See info in area-owners.md if you want to be subscribed.
/cc @pavelsavara
cc @kg
I believe the root cause here is that bool
in .NET is sometimes 4 bytes in size, not 1 byte, so by doing MarshalAs you're requiring pinvoke to make a temporary copy of your struct with a different size and copy all the values into it, performing truncation on the bools as needed. We generally don't support this kind of struct marshaling on WASM, at least not yet.
Also note that bool
is not a blittable type according to https://learn.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types. Right now you should only expect blittable structs to marshal properly on the wasm target. We may be able to relax these restrictions in the future. These limitations are due to the extreme complexity of p/invoke and the existing implementations not being directly portable to the WASM target.
As a workaround, consider wrapping the bytes with bool properties. That would maintain a blittable struct (with private byte fields) that has a public interface with bools in it.
you might be able to set the DisableRuntimeMarshalingAttribute on the assembly to make a struct containing a bool blittable (the MarshalAsAttribute must not be used then - it will use the underlying type (ie byte) as the marshaling type) https://github.com/dotnet/runtime/issues/60639 this is assuming all your pinvokes in the assembly are using the source generator [LibraryImport]
mechanism instead of the runtime built-in marshaling
Description
I am still determining if this is a runtime bug, but since this code works everywhere except Blazor WASM, I have to ask.
I am working on a program with a native library. It includes the following struct:
https://github.com/drasticactions/DA.Whisper/blob/wasm-bug/src/DA.Whisper/NativeMethods.g.cs#L380C5-L391C6
This can be retrieved by calling
NativeMethods.whisper_context_default_params();
to get the default values. I have built the native library on Windows, Mac, and Linux and invoked it in .NET (with and without NativeAOT enabled), and it has worked fine. Nothing is thrown, and I can manipulate the object and send it back though theNativeMethods
.However, when I built Whisper.cpp with Emscripten and ran it in web assembly, any time I called for any struct that included a
bool
, I would get aSystem.InvalidProgramException
with a blank message.I am unsure how to get better exceptions out of this, this is all I've been able to get. Other functions of accessing the library that don't involve these structs works as expected. Once I saw that it only through this message when I accessed the struct, I changed it to remove the Marshaling and set it to
byte
https://github.com/drasticactions/DA.Whisper/blob/wasm-bug/src/DA.Whisper/NativeMethods.g.cs#L367-L378
Everything started working! I got the struct, manipulated it, and sent it back through
NativeMethods
and Whisper loaded it fine.So I think that means there is a bug with
[MarshalAs(UnmanagedType.U1)]
and WASM. That should a byte (and indeed, it works on the other platforms I've tried, although maybe that's a mistake too?). I wish to keep my code the same to use the marshal value instead of byte (since it works everywhere else). Is this a bug, or did I make a mistake?I checked with both
net8.0
andnet9.0-preview7
and both fail with the same exception.Reproduction Steps
wasm-bug
branchmake wasm
(or use my provided runtimes, replace theruntime
folder with this runtime.zip)src\DA.WhisperBlazor
There are two buttons, one which invokes the Marshaled byte struct, the other which does not. Clicking on the First button should go through right, clicking the second should throw an exception.
Expected behavior
I can access Bool values in Native code via
[MarshalAs(UnmanagedType.U1)]
Actual behavior
System.InvalidProgramException
thrown.Regression?
No response
Known Workarounds
Don't use
[MarshalAs(UnmanagedType.U1)]
but use the literal typebyte
instead.Configuration
Other information
No response