cc-tweaked / Cobalt

A re-entrant fork of LuaJ
Other
72 stars 13 forks source link

Fix NEWTABLE instruction allocating incorrect array size #61

Closed Shiranuit closed 1 year ago

Shiranuit commented 1 year ago

What does this PR do ?

The NEWTABLE instruction had an issue where it was allocating the wrong amount of size for the array and nodes. The issue was parser was encoding array length and hash length using a floating point byte and the NEWTABLE instruction only reading the value as a byte without decoding it.

This caused some unexpected behaviour in some cases like the one bellow where Lua is stuck in the for loop because of next not behaving correctly.

local val = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,[24]={}}
for k, v in pairs(val) do
    print(k) -- This prints all the values from 1 to 18 then it loop indefinitely on the 24th element inside the nodes part
end

What happens is

SquidDev commented 1 year ago

Oh wow, this is an amazing PR. Thank you so much investigating, fixing, and then writing things up!

One thing which concerns here is that the table having the wrong size shouldn't cause the subsequent SETLIST instruction to fail. I think we should probably also change presize to use the underlying resize function (which is what PUC Lua does). I think this patch looks reasonable:

--- a/src/main/java/org/squiddev/cobalt/LuaTable.java
+++ b/src/main/java/org/squiddev/cobalt/LuaTable.java
@@ -186,7 +186,7 @@ public final class LuaTable extends LuaValue {
         */
        public void presize(int nArray) {
                if (nArray > array.length) {
-                       array = setArrayVector(array, 1 << log2(nArray), false, weakValues);
+                       resize(getHashLength(), 1 << log2(nArray), false);
                }
        }
Shiranuit commented 1 year ago

@SquidDev

One thing which concerns here is that the table having the wrong size shouldn't cause the subsequent SETLIST instruction to fail. I think we should probably also change presize to use the underlying resize function (which is what PUC Lua does). I think this patch looks reasonable:

--- a/src/main/java/org/squiddev/cobalt/LuaTable.java
+++ b/src/main/java/org/squiddev/cobalt/LuaTable.java
@@ -186,7 +186,7 @@ public final class LuaTable extends LuaValue {
         */
        public void presize(int nArray) {
                if (nArray > array.length) {
-                       array = setArrayVector(array, 1 << log2(nArray), false, weakValues);
+                       resize(getHashLength(), 1 << log2(nArray), false);
                }
        }

Yes, I agree it would be better to use resize instead of presize, it will lead to much less errors with the allocations.

Unfortunately in the case described earlier it wouldn't have made a difference, since SETLIST did not fail but assumed that it had to realloc the array since the size given by NEWTABLE was smaller than the size SETLIST obtained, which had the effect to override the size that the parser wanted to allocate specifically for the array because the array is static (until an insertion/deletion occurs).

SquidDev commented 1 year ago

Sorry, by fail I meant "produce a malformed table", not error or anything!

I think we should probably apply both patches, as both NEWLIST and presize are broken in different ways :D.