Skip to content

Commit be50402

Browse files
committed
tests/lapi: table tests
The patch adds a fuzzing tests for Lua table functions.
1 parent 5ab0975 commit be50402

11 files changed

+337
-0
lines changed

.luacheckrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ files["tests/capi/luaL_loadbuffer_proto/preamble.lua"] = {
55
"211",
66
},
77
}
8+
9+
globals = {
10+
table = {
11+
fields = { "create" }
12+
}
13+
}

tests/lapi/table_concat_test.lua

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--[=[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
6.6 – Table Manipulation
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
Infinite loop on table lookup,
9+
https://github.com/LuaJIT/LuaJIT/issues/494
10+
11+
Synopsis: table.concat(list [, sep [, i [, j]]])
12+
--]=]
13+
14+
local luzer = require("luzer")
15+
local test_lib = require("lib")
16+
17+
local function TestOneInput(buf, _size)
18+
local fdp = luzer.FuzzedDataProvider(buf)
19+
local str = fdp:consume_string(test_lib.MAX_STR_LEN)
20+
local tbl_size = #str
21+
-- io.stderr:write(tbl_size .. "\n")
22+
if tbl_size <= 1 then
23+
return -1
24+
end
25+
local tbl = {}
26+
str:gsub(".", function(c)
27+
table.insert(tbl, c)
28+
end)
29+
assert(#tbl, tbl_size)
30+
-- local j = fdp:consume_integer(1, tbl_size)
31+
-- local i = fdp:consume_integer(1, j)
32+
-- local sep = ""
33+
-- io.stderr:write(string.gsub(str, i, j) .. table.concat(tbl, sep, i, j) .. "\n")
34+
-- assert(string.gsub(str, i, j) == table.concat(tbl, sep, i, j))
35+
end
36+
37+
local args = {
38+
artifact_prefix = "table_concat_",
39+
}
40+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_create_test.lua

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
Bad lookup generated by lj_record_idx in GC64,
6+
https://github.com/LuaJIT/LuaJIT/issues/840
7+
8+
Synopsis:
9+
LuaJIT: table.new(narray, nhash)
10+
PUC Rio Lua: table.create(narray, nhash)
11+
]]
12+
13+
local luzer = require("luzer")
14+
local test_lib = require("lib")
15+
16+
local table_create
17+
if test_lib.lua_version() == "LuaJIT" then
18+
table_create = require("table.new")
19+
elseif test_lib.lua_current_version_lt_than(5, 5) then
20+
-- New function 'table.create()' in PUC Rio Lua,
21+
-- https://github.com/lua/lua/commit/3e9dbe143d3338f5f13a5e421ea593adff482da0
22+
table_create = table.create
23+
else
24+
print("Unsupported version.")
25+
os.exit(0)
26+
end
27+
28+
local function TestOneInput(buf)
29+
local fdp = luzer.FuzzedDataProvider(buf)
30+
-- Beware, huge number triggers OOM or table overflow.
31+
local MAX_N = 1000
32+
local narray = fdp:consume_integer(0, MAX_N)
33+
local nhash = fdp:consume_integer(0, MAX_N)
34+
local _ = table_create(narray, nhash) -- luacheck: no unused
35+
end
36+
37+
local args = {
38+
artifact_prefix = "table_create_",
39+
}
40+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_foreach_test.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
Bad loop initialization in table.foreach(),
6+
https://github.com/LuaJIT/LuaJIT/issues/844
7+
8+
string.dump(table.foreach) will trigger an assert,
9+
https://github.com/LuaJIT/LuaJIT/issues/1038
10+
11+
Synopsis: table.foreach(table, f)
12+
]]
13+
14+
local luzer = require("luzer")
15+
local test_lib = require("lib")
16+
17+
-- Function `table.foreach` is deprecated in Lua 5.1.
18+
if test_lib.lua_current_version_ge_than(5, 2) then
19+
print("Unsupported version.")
20+
os.exit(0)
21+
end
22+
23+
local function TestOneInput(buf, _size)
24+
local fdp = luzer.FuzzedDataProvider(buf)
25+
local count = fdp:consume_integer(1, test_lib.MAX_INT)
26+
local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count)
27+
local i = 0
28+
local fn = function(_idx) i = i + 1 end
29+
table.foreach(tbl, fn)
30+
assert(table.maxn(tbl) == i)
31+
end
32+
33+
local args = {
34+
artifact_prefix = "table_foreach_",
35+
}
36+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_insert_test.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2024, Sergey Bronnikov.
4+
5+
6.6 – Table Manipulation
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
Synopsis: table.insert(list, [pos,] value)
9+
]]
10+
11+
local luzer = require("luzer")
12+
13+
local function TestOneInput(buf, _size)
14+
local len = string.len(buf)
15+
local tbl = {}
16+
local pos = 1
17+
buf:gsub(".", function(c)
18+
table.insert(tbl, pos, c)
19+
pos = pos + 1
20+
end)
21+
assert(pos, len)
22+
end
23+
24+
local args = {
25+
artifact_prefix = "table_insert_",
26+
}
27+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_maxn_test.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
Synopsis: table.maxn(table)
6+
]]
7+
8+
local luzer = require("luzer")
9+
local test_lib = require("lib")
10+
11+
if test_lib.lua_current_version_ge_than(5, 3) then
12+
print("Unsupported version.")
13+
os.exit(0)
14+
end
15+
16+
local function TestOneInput(buf)
17+
local fdp = luzer.FuzzedDataProvider(buf)
18+
local count = fdp:consume_integer(0, test_lib.MAX_INT64)
19+
local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count)
20+
local maxn = table.maxn(tbl)
21+
assert(type(maxn) == "number")
22+
end
23+
24+
local args = {
25+
artifact_prefix = "table_maxn_",
26+
}
27+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_move_test.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
Synopsis: table.move(a1, f, e, t [,a2])
6+
]]
7+
8+
local luzer = require("luzer")
9+
local test_lib = require("lib")
10+
11+
if test_lib.lua_version() ~= "LuaJIT" then
12+
print("Unsupported version.")
13+
os.exit(0)
14+
end
15+
16+
local function TestOneInput(buf, _size)
17+
local fdp = luzer.FuzzedDataProvider(buf)
18+
local count = fdp:consume_integer(0, test_lib.MAX_INT)
19+
local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count)
20+
table.move(tbl, 1, #tbl, 1, {})
21+
end
22+
23+
local args = {
24+
artifact_prefix = "table_move_",
25+
}
26+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_pack_test.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
6.6 – Table Manipulation
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
Synopsis: table.pack(...)
9+
]]
10+
11+
local luzer = require("luzer")
12+
local test_lib = require("lib")
13+
14+
if test_lib.lua_current_version_lt_than(5, 2) then
15+
print("Unsupported version.")
16+
os.exit(0)
17+
end
18+
19+
local unpack = unpack or table.unpack
20+
21+
local function TestOneInput(buf, _size)
22+
local fdp = luzer.FuzzedDataProvider(buf)
23+
-- Beware, huge number triggers 'too many results to unpack'.
24+
local MAX_N = 1000
25+
local count = fdp:consume_integer(1, MAX_N)
26+
local tbl = fdp:consume_integers(test_lib.MIN_INT, test_lib.MAX_INT, count)
27+
local packed = table.pack(unpack(tbl))
28+
assert(#packed == #tbl)
29+
assert(packed[1] == tbl[1])
30+
end
31+
32+
local args = {
33+
artifact_prefix = "table_pack_",
34+
}
35+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_remove_test.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
6.6 – Table Manipulation
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
table.remove removes last element of a table when given an out-of-bound index,
9+
https://www.lua.org/bugs.html#5.1.2-10
10+
11+
Synopsis: table.remove(list [, pos])
12+
]]
13+
14+
local luzer = require("luzer")
15+
local test_lib = require("lib")
16+
local MAX_INT = test_lib.MAX_INT
17+
18+
local function TestOneInput(buf, _size)
19+
local fdp = luzer.FuzzedDataProvider(buf)
20+
local max_len = fdp:consume_integer(0, MAX_INT)
21+
local str = fdp:consume_string(max_len)
22+
local tbl = {}
23+
str:gsub(".", function(c)
24+
table.insert(tbl, c)
25+
end)
26+
for _ = 1, #tbl do
27+
assert(tbl[1] == table.remove(tbl, 1))
28+
end
29+
assert(#tbl == 0)
30+
end
31+
32+
local args = {
33+
artifact_prefix = "table_remove_",
34+
}
35+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_sort_test.lua

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
6.6 – Table Manipulation
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
'table.sort' does not work for partial orders,
9+
https://github.com/lua/lua/commit/825ac8eca8e384d6ad2538b5670088c31e08a9d7
10+
11+
Synopsis: table.sort(list [, comp])
12+
]]
13+
14+
local luzer = require("luzer")
15+
local test_lib = require("lib")
16+
17+
local function TestOneInput(buf, _size)
18+
local fdp = luzer.FuzzedDataProvider(buf)
19+
local max = fdp:consume_integer(0, test_lib.MAX_INT64)
20+
local min = fdp:consume_integer(test_lib.MIN_INT64, 0)
21+
local count = fdp:consume_integer(0, 1000)
22+
local tbl = fdp:consume_integers(min, max, count)
23+
table.sort(tbl)
24+
end
25+
26+
local args = {
27+
artifact_prefix = "table_sort_",
28+
}
29+
luzer.Fuzz(TestOneInput, nil, args)

0 commit comments

Comments
 (0)