zxh0/luago-book

LuaStack的Set函数忽略了idx等于top的情况

King19931229 opened this issue · 4 comments

存在如下Lua字节码:

main hello.lua:0,0 (69 instructions at 005f8670)
0+ params, 14 slots, 1 upvalue, 8 locals, 9 constants, 3 functions
1 [10] CLOSURE 0 0 ; 005f8880
2 [13] CLOSURE 1 1 ; 005f8a98
3 [12] SETTABUP 0 -1 1 ; _ENV "fail"
4 [17] CLOSURE 1 2 ; 005f8af0
5 [19] MOVE 2 0
..................................................................................................................
..................................................................................................................
..................................................................................................................

原来的Set函数忽略了idx == top的情况
对于上面的CLOSURE与MOVE指令运行都会失败

以下是C++版本的修复方法

void Set(int idx, const LuaValue& value)
{
	int absIdx = AbsIndex(idx);

	if(absIdx == top + 1)
		++top;

	if(absIdx > 0 && absIdx <= top)
	{
		slots[absIdx - 1] = value;
	}
	else
	{
		panic("invalid index!");
	}
}
zxh0 commented

非常感谢提供反馈,能否提供一个最小化的Lua脚本,重现问题。

非常感谢提供反馈,能否提供一个最小化的Lua脚本,重现问题。

我是用lua 5.3.6重现的
代码是第8章最后的lua测试代码

local function max(...)
local args = {...}
local val, idx
for i = 1, #args do
if val == nil or args[i] > val then
val, idx = args[i], i
end
end
return val, idx
end

local function fail()
end

local function assert(v)
if not v then fail() end
end

local v1 = max(3, 9, 7, 128, 35)
assert(v1 == 128)
local v2, i2 = max(3, 9, 7, 128, 35)
assert(v2 == 128 and i2 == 4)
local v3, i3 = max(max(3, 9, 7, 128, 35))
assert(v3 == 128 and i3 == 1)
local t = {max(3, 9, 7, 128, 35)}
assert(t[1] == 128 and t[2] == 4)

main hello.lua:0,0 (68 instructions at 004f8670)
0+ params, 15 slots, 1 upvalue, 9 locals, 8 constants, 3 functions
1 [10] CLOSURE 0 0 ; 004f8868
2 [13] CLOSURE 1 1 ; 004f8a80
3 [17] CLOSURE 2 2 ; 004f8ad8
4 [19] MOVE 3 0
5 [19] LOADK 4 -1 ; 3
6 [19] LOADK 5 -2 ; 9
7 [19] LOADK 6 -3 ; 7
8 [19] LOADK 7 -4 ; 128
9 [19] LOADK 8 -5 ; 35
10 [19] CALL 3 6 2
11 [20] MOVE 4 2
12 [20] EQ 1 3 -4 ; - 128
13 [20] JMP 0 1 ; to 15
14 [20] LOADBOOL 5 0 1
15 [20] LOADBOOL 5 1 0
16 [20] CALL 4 2 1
17 [21] MOVE 4 0
18 [21] LOADK 5 -1 ; 3
19 [21] LOADK 6 -2 ; 9
20 [21] LOADK 7 -3 ; 7
21 [21] LOADK 8 -4 ; 128
22 [21] LOADK 9 -5 ; 35
23 [21] CALL 4 6 3
24 [22] MOVE 6 2
25 [22] EQ 0 4 -4 ; - 128
26 [22] JMP 0 2 ; to 29
27 [22] EQ 1 5 -6 ; - 4
28 [22] JMP 0 1 ; to 30
29 [22] LOADBOOL 7 0 1
30 [22] LOADBOOL 7 1 0
31 [22] CALL 6 2 1
32 [23] MOVE 6 0
33 [23] MOVE 7 0
34 [23] LOADK 8 -1 ; 3
35 [23] LOADK 9 -2 ; 9
36 [23] LOADK 10 -3 ; 7
37 [23] LOADK 11 -4 ; 128
38 [23] LOADK 12 -5 ; 35
39 [23] CALL 7 6 0
40 [23] CALL 6 0 3
41 [24] MOVE 8 2
42 [24] EQ 0 6 -4 ; - 128
43 [24] JMP 0 2 ; to 46
44 [24] EQ 1 7 -7 ; - 1
45 [24] JMP 0 1 ; to 47
46 [24] LOADBOOL 9 0 1
47 [24] LOADBOOL 9 1 0
48 [24] CALL 8 2 1
49 [25] NEWTABLE 8 0 0
50 [25] MOVE 9 0
51 [25] LOADK 10 -1 ; 3
52 [25] LOADK 11 -2 ; 9
53 [25] LOADK 12 -3 ; 7
54 [25] LOADK 13 -4 ; 128
55 [25] LOADK 14 -5 ; 35
56 [25] CALL 9 6 0
57 [25] SETLIST 8 0 1 ; 1
58 [26] MOVE 9 2
59 [26] GETTABLE 10 8 -7 ; 1
60 [26] EQ 0 10 -4 ; - 128
61 [26] JMP 0 3 ; to 65
62 [26] GETTABLE 10 8 -8 ; 2
63 [26] EQ 1 10 -6 ; - 4
64 [26] JMP 0 1 ; to 66
65 [26] LOADBOOL 10 0 1
66 [26] LOADBOOL 10 1 0
67 [26] CALL 9 2 1
68 [26] RETURN 0 1

function hello.lua:1,10 (21 instructions at 004f8868)
0+ params, 8 slots, 0 upvalues, 7 locals, 2 constants, 0 functions
1 [2] NEWTABLE 0 0 0
2 [2] VARARG 1 0
3 [2] SETLIST 0 0 1 ; 1
4 [3] LOADNIL 1 1
5 [4] LOADK 3 -1 ; 1
6 [4] LEN 4 0
7 [4] LOADK 5 -1 ; 1
8 [4] FORPREP 3 8 ; to 17
9 [5] EQ 1 1 -2 ; - nil
10 [5] JMP 0 3 ; to 14
11 [5] GETTABLE 7 0 6
12 [5] LT 0 1 7
13 [5] JMP 0 3 ; to 17
14 [6] GETTABLE 7 0 6
15 [6] MOVE 2 6
16 [6] MOVE 1 7
17 [4] FORLOOP 3 -9 ; to 9
18 [9] MOVE 3 1
19 [9] MOVE 4 2
20 [9] RETURN 3 3
21 [10] RETURN 0 1

function hello.lua:12,13 (1 instruction at 004f8a80)
0 params, 2 slots, 0 upvalues, 0 locals, 0 constants, 0 functions
1 [13] RETURN 0 1

function hello.lua:15,17 (5 instructions at 004f8ad8)
1 param, 2 slots, 1 upvalue, 1 local, 0 constants, 0 functions
1 [16] TEST 0 1
2 [16] JMP 0 2 ; to 5
3 [16] GETUPVAL 1 0 ; fail
4 [16] CALL 1 1 1
5 [17] RETURN 0 1

zxh0 commented

上面的格式看起来非常痛苦,能否进一步说明一下问题,是这段脚本用书里代码跑的结果,和lua 5.3.6跑的结果不一样?多谢啦

上面的格式看起来非常痛苦,能否进一步说明一下问题,是这段脚本用书里代码跑的结果,和lua 5.3.6跑的结果不一样?多谢啦

应该跟我在 #23 提的issule是同一个问题
看前4条指令
1 [10] CLOSURE 0 0 ; 004f8868
2 [13] CLOSURE 1 1 ; 004f8a80
3 [17] CLOSURE 2 2 ; 004f8ad8
4 [19] MOVE 3 0
这里都是修改栈元素的,但是并没有修改到top
但是luaStack的top方法又要判断top
func (self *luaStack) get(idx int) luaValue {
absIdx := self.absIndex(idx)
if absIdx > 0 && absIdx <= self.top {
return self.slots[absIdx-1]
}
return nil
}
所以这里感觉有矛盾
我的修复方式是在get那里把top也修改了
这是这种改法修复不了 #23 的问题
现在我把

if(absIdx == top + 1)
	++top;

又修改为

while(absIdx > top)
	++top;

或者是

if(absIdx > top)
	top = absIdx;

感觉是在打补丁