-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
SEHException with new Exception behavior in .NET 9 #111242
Comments
Rust |
The problem is interesting. At the point .NET gets notified about the error raised by Lua, the call stack looks as shown below. The key point is that there is a block of Lua frames, then a block of .NET managed frames, then again a block of Lua frames and then again .NET managed frames. I need to figure out how to preserve the exception code to rethrow and then rethrow the original SEH exception.
|
It is even more interesting. Re-raising the same SEH exception as .NET got notified about doesn't help for this case, because longjmp doesn't actually use RaiseException. So we will need to re-issue the longjmp, extracting the arguments from the |
So we cannot ignore it, the old EH also doesn't ignore it, so there can be e.g. finally handlers invoked while the longjmp jumps over managed frames. I've experimented with re-running longjmp instead of doing RaiseException when the exception escapes managed frames and is propagated into native ones and it seems to work correctly. |
Using longjump to skip over managed frames had all sort of issues, even in the old EH scheme. We have it explicitly documented as unsupported in https://learn.microsoft.com/en-us/dotnet/standard/native-interop/exceptions-interoperability#setjmplongjmp-behaviors |
Ok, then I guess that fixing this specific issue by making it just skip over the managed frames without invoking finallys is the right way to do it. That would be also aligned with Unix where we could not even see there is a longjmp over managed frames. |
The new exception handling has broken hosting Lua on Windows when a Lua code throws an exception that ends up crossing managed frames. Lua uses longjmp for its exception handling mechanism and the new exception handling reported the longjmp as an unhandled `SEHException`. This change makes the new EH ignore the `STATUS_LONGJUMP` exception when it passes through managed frames, so it can reach the target location. It is a best effort fix though, as finallys in the skipped frames won't be called. Close dotnet#111242
On Unix, longjump does not work at all since we are not able to unwind transition frames. It means that the key runtime data structures get corrupted and you are very likely going to crash soon after. #1445 has an example of the crash that it leads to. |
Description
Starting in .NET 9, pinvoking Lua's
luaL_error
can raise aSEHException
.I believe this is due to
luaL_error
being a relatively thin wrapper overlongjmp
.I narrowed this down to the newly defaulted on improved exception handling in .NET 9.
Note that while I use KeraLua in my repro, the same thing happens if you pinvoke Lua directly - KeraLua is just a convenient way to package up a pre-built Lua 5.4 binary, and eliminate some of my own pinvoke definition from the repro.
Reproduction Steps
csproj
Program.cs
Expected behavior
Expected behavior is either the .NET 8:
or .NET 9 with DOTNET_LegacyExceptionHandling=1 behavior:
Where
luaL_error
works when pinvoked.Actual behavior
A
SEHException
is raised:Regression?
Yes, this worked in earlier versions of .NET. I have confirmed it worked in .NET 8, and this was reported when first running the code on .NET 9.
Known Workarounds
Setting DOTNET_LegacyExceptionHandling=1 fixes the issue in .NET 9.
Discussion on the PR that introduced it suggests it is temporary however, if it is removed in a later .NET release we will no longer have a workaround.
Configuration
Other information
While I admit longjmp is weird, embedding Lua is pretty popular.
The text was updated successfully, but these errors were encountered: