moonsharp-devs / moonsharp

An interpreter for the Lua language, written entirely in C# for the .NET, Mono, Xamarin and Unity3D platforms, including handy remote debugger facilities.
http://www.moonsharp.org
Other
1.42k stars 214 forks source link

System.IndexOutOfRangeException #218

Open wledfor2 opened 7 years ago

wledfor2 commented 7 years ago

I was writing a wrapper around NUnit's assert functions, I encountered a strange issue. When running the following code:

using System;
using MoonSharp.Interpreter;
using NUnit.Framework;

namespace Test {

    class Test {

        public class TestClass {

            //simple wrapper around NUnit.Framework.Assert.Catch
            public DynValue Catch(DynValue testDelegate, DynValue message) {
                Exception e = Assert.Catch(() => testDelegate.Function.Call(), message.CastToString());
                return DynValue.NewTuple(DynValue.NewString(e.GetType().Name), DynValue.NewString(e.Message));

            }

        }

        public static void Main(string[] args) {

            try {

                UserData.RegisterType<TestClass>();
                Script s = new Script();
                s.Globals["Assert"] = UserData.Create(new TestClass());
                s.DoString(@"

                    -- does not throw, because function argument throws
                    Assert:Catch(

                        -- AssertionException bubbles up
                        function()

                            -- throws AssertionException, because function argument does not throw
                            Assert:Catch(

                                -- does not throw
                                function()
                                end

                            )

                        end

                    )

                ");

            } catch (InterpreterException e) {

                Console.WriteLine(e.DecoratedMessage);

            }
        }
    }
}

The following exception is produced:

Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at MoonSharp.Interpreter.Execution.VM.Processor.AssignLocal(SymbolRef symref, DynValue value) in src\MoonSharp.Interpreter\Execution\VM\Processor\Processor_InstructionLoop.cs:line 358
   at MoonSharp.Interpreter.Execution.VM.Processor.ExecStoreLcl(Instruction i) in src\MoonSharp.Interpreter\Execution\VM\Processor\Processor_InstructionLoop.cs:line 370
   at MoonSharp.Interpreter.Execution.VM.Processor.Processing_Loop(Int32 instructionPtr) in src\MoonSharp.Interpreter\Execution\VM\Processor\Processor_InstructionLoop.cs:line 210
   at MoonSharp.Interpreter.Execution.VM.Processor.Call(DynValue function, DynValue[] args) in src\MoonSharp.Interpreter\Execution\VM\Processor\Processor.cs:line 67
   at MoonSharp.Interpreter.Script.Call(DynValue function, DynValue[] args) in src\MoonSharp.Interpreter\Script.cs:line 483
   at MoonSharp.Interpreter.Script.Call(DynValue function) in src\MoonSharp.Interpreter\Script.cs:line 442
   at MoonSharp.Interpreter.Script.DoString(String code, Table globalContext, String codeFriendlyName) in src\MoonSharp.Interpreter\Script.cs:line 331
   at Test.Test.Main(String[] args) in Program.cs:line 29

When changing the Lua code to this, it works as expected:

Assert:Catch(function()
    Assert:Catch(function()
    end)
end)

or

return Assert:Catch(function()
    Assert:Catch(function()
    end)
end)

and accept return values from DoString, the results are as expected.

wledfor2 commented 7 years ago

The issue isn't just NUnit. It happens when any exception but ScriptRuntimeException is thrown.

//this works
public DynValue Catch(DynValue testDelegate, DynValue message) {

    Exception e = null;

    try {

        testDelegate.Function.Call();

    } catch(Exception ex) {

        e = ex;

    }

    if (e == null) {

        throw new ScriptRuntimeException(message.CastToString());

    }

    return DynValue.NewTuple(DynValue.NewString(e.GetType().Name), DynValue.NewString(e.Message));

}
//this does not work
public DynValue Catch(DynValue testDelegate, DynValue message) {

    Exception e = null;

    try {

        testDelegate.Function.Call();

    } catch(Exception ex) {

        e = ex;

    }

    if (e == null) {

        throw new Exception(message.CastToString());

    }

    return DynValue.NewTuple(DynValue.NewString(e.GetType().Name), DynValue.NewString(e.Message));

}

I'm not sure what's going on here.