diff --git a/src/Lua/Runtime/LuaVirtualMachine.cs b/src/Lua/Runtime/LuaVirtualMachine.cs index 3d28c283..2772febe 100644 --- a/src/Lua/Runtime/LuaVirtualMachine.cs +++ b/src/Lua/Runtime/LuaVirtualMachine.cs @@ -170,7 +170,7 @@ public bool PopFromBuffer(int src, int srcCount) // Other opcodes has one result default: Stack.Get(target) = result.Length == 0 ? LuaValue.Nil : result[0]; - State.PopCallStackFrameWithStackPop(target + 1); + State.PopCallStackFrameWithStackPop(Math.Max(target + 1, CurrentReturnFrameBase)); return true; } diff --git a/tests/Lua.Tests/LoopTests.cs b/tests/Lua.Tests/LoopTests.cs index dd791cd5..f8c28311 100644 --- a/tests/Lua.Tests/LoopTests.cs +++ b/tests/Lua.Tests/LoopTests.cs @@ -1,3 +1,5 @@ +using Lua.Standard; + namespace Lua.Tests; public class LoopTests @@ -49,4 +51,47 @@ public async Task Test_While() Assert.That(result, Has.Length.EqualTo(1)); Assert.That(result[0], Is.EqualTo(new LuaValue(100))); } + + [Test] + public async Task Test_NumericFor_MetamethodResultDoesNotCorruptLoopState() + { + var source = + @" +local mt = {} +mt.__add = function(a, b) return setmetatable({ v = a.v + b.v }, mt) end +local acc = setmetatable({ v = 0 }, mt) +for i = 1, 5 do + acc = acc + setmetatable({ v = i }, mt) +end +return acc.v"; + + var state = LuaState.Create(); + state.OpenStandardLibraries(); + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + var result = await state.DoStringAsync(source, "@test.lua", cts.Token); + + Assert.That(result, Has.Length.EqualTo(1)); + Assert.That(result[0], Is.EqualTo(new LuaValue(15))); + } + + [Test] + public async Task Test_NumericFor_IndexMetamethodResultDoesNotCorruptLoopState() + { + var source = + @" +local proxy = setmetatable({}, { __index = function(_, k) return k end }) +local sum = 0 +for i = 1, 5 do + sum = sum + proxy[i] +end +return sum"; + + var state = LuaState.Create(); + state.OpenStandardLibraries(); + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + var result = await state.DoStringAsync(source, "@test.lua", cts.Token); + + Assert.That(result, Has.Length.EqualTo(1)); + Assert.That(result[0], Is.EqualTo(new LuaValue(15))); + } }