Description
Description
Starting in .NET 9, pinvoking Lua's luaL_error
can raise a SEHException
.
I believe this is due to luaL_error
being a relatively thin wrapper over longjmp
.
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
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="KeraLua" Version="1.4.1" />
</ItemGroup>
</Project>
Program.cs
using KeraLua;
namespace LongJumpRepro
{
public class Program
{
private const string ErrorMsg = "!!RAISED!!";
private static Lua? lua;
public static void Main(string[] args)
{
// This works as expected in .NET 8
// It raises a SEHException in .NET 9
// The exception in .NET 9 goes away if you set environment variable DOTNET_LegacyExceptionHandling=1
Console.WriteLine($".NET version: {Environment.Version}");
Console.WriteLine($"DOTNET_LegacyExceptionHandling: {Environment.GetEnvironmentVariable("DOTNET_LegacyExceptionHandling")}");
try
{
lua = new Lua();
lua.PushCFunction(RaiseLuaError);
var status = lua.PCall(0, 0, 0);
Console.WriteLine($"Status (Expected {LuaStatus.ErrRun}): {status}");
var errMsg = lua.CheckString(1);
Console.WriteLine($"Error Message (Expected '{ErrorMsg}'): {ErrorMsg}");
}
finally
{
lua?.Dispose();
}
}
private static int RaiseLuaError(nint luaState)
=> lua!.Error(ErrorMsg);
}
}
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
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
- .NET 8 and .NET 9
- Windows 11
- x64
- I have not tested on other configurations
- I am not using Blazor
Other information
While I admit longjmp is weird, embedding Lua is pretty popular.