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)
     public static void BadArgument(LuaThread? thread, int argumentId, string functionName)
     {
     {
         throw new LuaRuntimeException(thread, $"bad argument #{argumentId} to '{functionName}' (value expected)");
         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)]
     [MethodImpl(MethodImplOptions.NoInlining)]
     static bool GetTableValueSlowPath(LuaValue table, LuaValue key, VirtualMachineExecutionContext context, out LuaValue value, out bool doRestart)
     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;
         var targetTable = table;
         const int MAX_LOOP = 100;
         const int MAX_LOOP = 100;
         doRestart = false;
         doRestart = false;
@@ -1644,6 +1655,21 @@ public static partial class LuaVirtualMachine
     static bool SetTableValueSlowPath(LuaValue table, LuaValue key, LuaValue value,
     static bool SetTableValueSlowPath(LuaValue table, LuaValue key, LuaValue value,
         VirtualMachineExecutionContext context, out bool doRestart)
         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;
         var targetTable = table;
         const int MAX_LOOP = 100;
         const int MAX_LOOP = 100;
         doRestart = false;
         doRestart = false;
@@ -2403,7 +2429,7 @@ public static partial class LuaVirtualMachine
     static void GetThreadWithCurrentPc(LuaThread thread, int pc)
     static void GetThreadWithCurrentPc(LuaThread thread, int pc)
     {
     {
         var frame = thread.GetCurrentFrame();
         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)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]