-
Notifications
You must be signed in to change notification settings - Fork 4.5k
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][Wasm][Interp] Assertion fail in Marshal.GetFunctionPointerForDelegate #101736
Comments
Add some extra info: Compile dotnet runtime under single thread. Build without SIMD enabled |
Tagging subscribers to this area: @BrzVlad, @kotlarmilos |
I'm going to provide more info here. I located the method to marshal and turned on Here's the IL diff containing jiterp&bblocks ON vs OFF. It seems certain instructions was taken as dead but should be kept? And the mis-removal would cause problem in jiterp optimization? In fact, with the hacking above. The program would work with only JITERP disabled @BrzVlad I completely understand that you might be swamped. But would you take a look and provide some insights when you have time? Thanks in advance! |
Thank you for taking the time to look into it. From the verbose log, it looks like the ldloca is generated with the incorrect source. The Are you sure you are using the latest net8 release ? |
@BrzVlad Thanks for the inputs! We are indeed not working on the latest net8 but a fork with Unity specific changes. I will apply the patch and get you with the results later. |
With the fix I can no longer see the BBLOCK optimization errors. Thanks again for the kind help! @BrzVlad But still the program is not running correctly unless I disable INTERP_OPT_JITERPRETER. I got memory access OOB with callstack I checked the method value in
Although the stack evaluation failed in |
d62ff0b This is the only commit my branch doesn't have but I think it is not related. And here is the mono verbose and jiterp stats log before MOOB
|
There have been some serious changes in this area in .net9. It would be worthwhile to try it out. Maybe @kg can provide some help with diagnosing this latest failure |
As a starting point, you could use MONO_VERBOSE_METHOD to dump IsUserCattrProvider. The jiterpreter should automatically engage its diagnostics for the method and we can examine what it's doing to see if it makes sense. |
@BrzVlad Thanks for the suggestion. In fact we started our project investigation with net9 alpha. The only reason we decided to use net8 is that it is officially released at the time. When do you think that net9 can be considered stable? We will definitely come back to integrate with net9 by then. localhost-1715442485731.log |
Is there a reason why it says |
Also, are you running any third party WASM code in your environment? This crash appears to indicate memory corruption, specifically the reserved low memory region in the WASM heap that's supposed to be all zeroes. If the low memory region is corrupted when the jiterpreter is enabled, that can turn NullReferenceExceptions into 'memory access out of bounds' errors. I refer to this area as the "zero page". If the zero page is being corrupted, you can disable zero page optimizations by turning off the You could also disable null check elimination, but in this case I don't think that's related. If I found the correct implementation of You could also examine the bottom of WASM memory in the devtools debugger when this crash happens. It should be all zeroes. |
@kg Yes there are third party natives, I'm working on Unity :) My team started to add a lot Unity specific changes on top of NET8 to make it work on WebGL platform without AOT (to keep a lower memory on mobile devices). In fact this issue comes from one of our clients. As we need a stable version and not sure if any recurssion issue may be introduced when applying the latest change of NET8, we just let the net8 stay on a specific version unless there are problems. And only the wasm changes are necessary for us. I will try the jiterp options first and try to merge the latest NET8 later. |
Confirmed that there is no MOOB when |
For the interim it should be safe to just run with that option turned off, and the performance penalty is pretty small (something like 1-5% for jiterpreter traces that do specific operations). |
Will try that temporarily for this specific project. Thanks for the help! |
I do not know of any good way to detect zero page corruption other than frequently verifying the zero page after invoking third party code. The jiterpreter does some basic checks of the zero page in order to identify this kind of corruption, and it will shut off the optimizations if it detects it. But it can't always detect it. Also, I believe we pass |
You are correct. I just checked the build binlog and found that As for the 3rd party codes, except for Unity engine native modules, 3rd party native libs are allowed to be involved in the build process. If this crash can be triggered by any 3rd party native(wasm), it seems disabling the zero page optimization would be the only way to ensure the game won't crash. |
Description
I was testing a project using
Marshal.GetFunctionPointerForDelegate
in both Debug and Release mode. The code fragment causing problem is:I first tested with wrapper func in Debug mode. It failed to find the native2managed function because
orig_method
is NULL inruntime/src/mono/mono/mini/interp/interp.c
Line 3327 in ca4f0fe
(I can understand somehow because both m2n or n2m function in pinvoke-table.h was generated at compile time. Lambda function may not contain necessary info. But is it a bug? )
So I removed the wrapper and marshal managedFn directly. I got no problem in Debug mode. However, I met assertion failure in Release mode:
runtime/src/mono/mono/mini/interp/transform.c
Line 9007 in ca4f0fe
(local_ref_count == 0 at the time)
(Normally a fatal error won't give me exact mono trace so that I changed the related runtime code by setting
mono_error_set_xxx
to continue the program. This helped me to get the managed stacktraces that caused the problem.)And after that I did some tests by comparing what made the difference between Debug and Release. Eventually I located the interp optimization options because I found the code path in Debug and Release mode was totally different. With "-jiterp,-bblocks" disabled, everything seems fine.
As I'm not an expert in mono, I do not quite understand the optimization logic which makes the debugging full of struggle. Is there any documents regarding the interp optimization logic? Help is needed!
Reproduction Steps
Just by called the managed code(after mono runtime is initialized of course)
Expected behavior
No error
Actual behavior
Assertion failed and program was terminated
Regression?
I've only tested in .NET 8. Not sure if the behaviour is the same in .NET9
Known Workarounds
Disable part of interp_opts. The minimum combination is to disable INTERP_OPT_JITERPRETER and INTERP_OPT_BBLOCKS.
It works fine in debug mode which I checked the source code that no interp_opts is enabled.
Configuration
.NET8
Wasm
Tested in Chrome/Edge (v8)
I haven't tested against Webkit, but I guess this may not be related to browser.
Other information
No response
The text was updated successfully, but these errors were encountered: