Как мне вызвать делегата C# из Lua, где делегат может создать исключение

#c# #lua #nlua

Вопрос:

Выполнение следующего кода в образе докера на базе Linux приводит к сбою среды CLR.

 static void Main(string[] args)
    {
        System.Console.WriteLine("Starting program");
        using (NLua.Lua luaState = new NLua.Lua())
        {
            System.Action invoke = () => throw new System.Exception("message");
            luaState["invoke"] = invoke;
            try
            {
                System.Console.WriteLine("Invoking delegate");
                luaState.DoString(@"invoke()");
            }
            catch (System.Exception ex)
            {
                // We never get here
                System.Console.WriteLine("Exception caught");
                throw;
            }
        }

    }
 

Я делаю что-то не так?

Файл Dockerfile-это предложение по умолчанию из Visual Studio, и процесс запускается из Visual Studio.

Запуск программы вне Docker, т. е. на хосте Windows работает так, как ожидалось. (Попадает в блок захвата и не вызывает фатального состояния на CLR)

Обертывание вызова в a pcall не решает проблему.

Можно избежать этой проблемы, зарегистрировав функции, а не отправив делегатов. Если делегат не создает исключение, оно вызывается, как и ожидалось.

Журнал консоли из образа;

 Starting program
Invoking delegate
Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.Exception: message
at LuaTest.Program.<>c.<Main>b__0_0() in C:SourceTestsLuaTestProgram.cs:line 10
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at NLua.MetaFunctions.CallDelegateInternal(Lua luaState)
at NLua.MetaFunctions.CallDelegate(IntPtr state)
at KeraLua.NativeMethods.lua_pcallk(IntPtr luaState, Int32 nargs, Int32 nresults, Int32 errorfunc, IntPtr ctx, IntPtr k)
at KeraLua.Lua.PCall(Int32 arguments, Int32 results, Int32 errorFunctionIndex)
at NLua.Lua.DoString(String chunk, String chunkName)
at LuaTest.Program.Main(String[] args) in C:SourceTestsLuaTestProgram.cs:line 15
Fatal error. Internal CLR error. (0x80131506)
at KeraLua.NativeMethods.lua_pcallk(IntPtr, Int32, Int32, Int32, IntPtr, IntPtr)
at KeraLua.NativeMethods.lua_pcallk(IntPtr, Int32, Int32, Int32, IntPtr, IntPtr)
at KeraLua.Lua.PCall(Int32, Int32, Int32)
at NLua.Lua.DoString(System.String, System.String)
at LuaTest.Program.Main(System.String[])
 

Комментарии:

1. Можете ли вы подтвердить, что у вас такое же поведение в Моно? IIRC CLR в Linux обрабатывает SEH иначе, чем Windows. Что приводит к сбою среды CLR setjmp/longjmp при развертывании стека.

2. @ViniciusJarina Mono продолжает жаловаться на отсутствие библиотеки dll Lua54. — Не уверен, что я делаю неправильно с процессом сборки здесь. Вы, вероятно, правы в том, что проблема заключается в longjmp.

Ответ №1:

Самостоятельный ответ;

Похоже, это ошибка в NLua MetaFunctions.CallDelegate . Вызов делегата не находится в блоке try-catch. Контраст с LuaMethodWrapper.Call .

Фатальная ошибка, вероятно, вызвана попыткой распространить исключение с помощью неуправляемого кода, который вызывает longjmp. См. Основную заметку dotnet о совместимости исключений

Наиболее прямым обходным путем является регистрация делегата с помощью функции register.

 Action action=()=>throw new Exception()
luastate.RegisterFunction("invoke",action.Target,action.Method);