Browse Source

fix: handle invalid operations on nil values in Lua table access

Akeit0 6 months ago
parent
commit
4a7cfb1fe3
2 changed files with 41 additions and 5 deletions
  1. 10 0
      src/Lua/Exceptions.cs
  2. 31 5
      src/Lua/Runtime/LuaVirtualMachine.cs

+ 10 - 0
src/Lua/Exceptions.cs

@@ -145,6 +145,16 @@ public class LuaRuntimeException : Exception, ILuaTracebackBuildable
         }
     }
 
+    internal static void AttemptInvalidOperationOnUpValues(LuaThread thread, string op, int lastPc, int reg)
+    {
+        var caller = thread.GetCurrentFrame();
+        var luaValue = thread.Stack[caller.Base + reg];
+        var function = caller.Function;
+        var name = ((LuaClosure)function).Proto.UpValues[reg].Name;
+
+        throw new LuaRuntimeException(thread, $"attempt to {op} a {luaValue.TypeToString()} value (global '{name}')");
+    }
+
     public static void BadArgument(LuaThread? thread, int argumentId, string functionName)
     {
         throw new LuaRuntimeException(thread, $"bad argument #{argumentId} to '{functionName}' (value expected)");

+ 31 - 5
src/Lua/Runtime/LuaVirtualMachine.cs

@@ -1482,10 +1482,21 @@ public static partial class LuaVirtualMachine
     [MethodImpl(MethodImplOptions.NoInlining)]
     static bool GetTableValueSlowPath(LuaValue table, LuaValue key, VirtualMachineExecutionContext context, out LuaValue value, out bool doRestart)
     {
-        // TODO: get table name if nil
-        // if (table.Type == LuaValueType.Nil)
-        // {
-        // }
+        if (table.Type == LuaValueType.Nil)
+        {
+            ThrowInvalidOperation();
+
+            [MethodImpl(MethodImplOptions.NoInlining)]
+            void ThrowInvalidOperation()
+            {
+                var op = context.Instruction.OpCode;
+                if (op != OpCode.GetTabUp)
+                    LuaRuntimeException.AttemptInvalidOperationOnLuaStack(GetThreadWithCurrentPc(context), "index", context.Pc, context.Instruction.B);
+                else
+                    LuaRuntimeException.AttemptInvalidOperationOnUpValues(GetThreadWithCurrentPc(context), "index", context.Pc, context.Instruction.B);
+            }
+        }
+
         var targetTable = table;
         const int MAX_LOOP = 100;
         doRestart = false;
@@ -1644,6 +1655,21 @@ public static partial class LuaVirtualMachine
     static bool SetTableValueSlowPath(LuaValue table, LuaValue key, LuaValue value,
         VirtualMachineExecutionContext context, out bool doRestart)
     {
+        if (table.Type == LuaValueType.Nil)
+        {
+            ThrowInvalidOperation();
+
+            [MethodImpl(MethodImplOptions.NoInlining)]
+            void ThrowInvalidOperation()
+            {
+                var op = context.Instruction.OpCode;
+                if (op != OpCode.SetTabUp)
+                    LuaRuntimeException.AttemptInvalidOperationOnLuaStack(GetThreadWithCurrentPc(context), "index", context.Pc, context.Instruction.A);
+                else
+                    LuaRuntimeException.AttemptInvalidOperationOnUpValues(GetThreadWithCurrentPc(context), "index", context.Pc, context.Instruction.A);
+            }
+        }
+
         var targetTable = table;
         const int MAX_LOOP = 100;
         doRestart = false;
@@ -2403,7 +2429,7 @@ public static partial class LuaVirtualMachine
     static void GetThreadWithCurrentPc(LuaThread thread, int pc)
     {
         var frame = thread.GetCurrentFrame();
-        thread.PushCallStackFrame(frame with { CallerInstructionIndex = pc,Flags = frame.Flags^ CallStackFrameFlags.TailCall });
+        thread.PushCallStackFrame(frame with { CallerInstructionIndex = pc, Flags = frame.Flags & (0 ^ CallStackFrameFlags.TailCall) });
     }
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]