From cfeb4429b43f4fd570d20970f18145a6ffee2db1 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Wed, 27 Aug 2025 16:55:51 +0300 Subject: [PATCH 1/8] cmake: bump luzer The patch bumps a luzer's version, full list of commits is in [1]. Notable changes are: - Fixed compilation with latest PUC Rio Lua 1. https://github.com/ligurio/luzer/compare/3f4eb03b4f..fc4a32fe98 Needed for #153 --- cmake/BuildLuzer.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/BuildLuzer.cmake b/cmake/BuildLuzer.cmake index e057697..833204b 100644 --- a/cmake/BuildLuzer.cmake +++ b/cmake/BuildLuzer.cmake @@ -34,7 +34,7 @@ endif() ExternalProject_Add(bundled-luzer GIT_REPOSITORY https://github.com/ligurio/luzer - GIT_TAG 3f4eb03b4ff7596855a0aaf45aa557f61b25ddb2 + GIT_TAG fc4a32fe98f1da8b07f74a35f40b678692e7152b GIT_PROGRESS TRUE GIT_SHALLOW FALSE SOURCE_DIR ${LUZER_DIR}/source From 5d2ee02448e8a63c1f652563b35e79bc02732bf2 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Mon, 28 Jul 2025 17:49:45 +0300 Subject: [PATCH 2/8] tests/lapi: fix table_remove_test Fix out-of-bound indices passed to `table.remove()`. --- tests/lapi/table_remove_test.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/lapi/table_remove_test.lua b/tests/lapi/table_remove_test.lua index 330d946..347e6b9 100644 --- a/tests/lapi/table_remove_test.lua +++ b/tests/lapi/table_remove_test.lua @@ -16,11 +16,17 @@ local test_lib = require("lib") local function TestOneInput(buf, _size) local fdp = luzer.FuzzedDataProvider(buf) - local count = fdp:consume_integer(0, test_lib.MAX_INT) + local count = fdp:consume_integer(1, test_lib.MAX_INT) local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count) local indices_count = fdp:consume_integer(0, #tbl) - local indices = fdp:consume_integers(0, count, indices_count) + local min_index = 0 + -- PUC Rio Lua 5.2+ raises an error "position out of bounds" + -- when `pos` is equal to 0 and table is not empty. + if test_lib.lua_current_version_ge_than(5, 2) then + min_index = 1 + end + local indices = fdp:consume_integers(min_index, count, indices_count) for _, idx in ipairs(indices) do local old_v = tbl[idx] assert(table.remove(tbl, idx) == old_v) From 1afca942f73d4ebb69370ac009a50b5673eefb86 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Mon, 28 Jul 2025 18:19:58 +0300 Subject: [PATCH 3/8] tests/lapi: fix string_byte_test The patch fixes the following issues: - `string.byte()` returns the internal numeric codes of the characters, not a single number. - `string.char()` returns `nil` when values `i` or `j` are outside the acceptable range (less than zero and greater than the length of the string). It is not documented. Follows up #124 --- tests/lapi/string_byte_test.lua | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/lapi/string_byte_test.lua b/tests/lapi/string_byte_test.lua index e309f72..b21726c 100644 --- a/tests/lapi/string_byte_test.lua +++ b/tests/lapi/string_byte_test.lua @@ -1,4 +1,4 @@ ---[[ +--[=[ SPDX-License-Identifier: ISC Copyright (c) 2023-2025, Sergey Bronnikov. @@ -7,9 +7,9 @@ https://www.lua.org/manual/5.3/manual.html#6.4 string.byte gets confused with some out-of-range negative indices, https://www.lua.org/bugs.html#5.1.3-9 -]] --- Synopsis: string.byte(s [, i [, j]]) +Synopsis: string.byte(s [, i [, j]]) +]=] local luzer = require("luzer") local test_lib = require("lib") @@ -18,17 +18,15 @@ local function TestOneInput(buf, _size) local fdp = luzer.FuzzedDataProvider(buf) os.setlocale(test_lib.random_locale(fdp), "all") local str = fdp:consume_string(test_lib.MAX_STR_LEN) - local i = fdp:consume_integer(0, test_lib.MAX_INT) - local j = fdp:consume_integer(0, test_lib.MAX_INT) + local i = fdp:consume_integer(test_lib.MIN_INT, test_lib.MAX_INT) + local j = fdp:consume_integer(test_lib.MIN_INT, test_lib.MAX_INT) -- `string.byte()` is the same as `str:byte()`. assert(string.byte(str, i, j) == str:byte(i, j)) - local char_code = string.byte(str, i, j) - if char_code then - assert(type(char_code) == "number") - local byte = string.char(char_code) - assert(byte) - assert(byte == str) - end + -- Note, `string.byte()` returns `nil` when values `i` or `j` + -- are outside the acceptable range (less than zero and + -- greater than the length of the string). It is undocumented. + local bytes = string.char(string.byte(str, i, j)) + assert(bytes == string.sub(str, i, j)) end local args = { From ef021a8f93b16b300d7a871cfc648de4224ce893 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Mon, 28 Jul 2025 18:20:09 +0300 Subject: [PATCH 4/8] tests/lapi: fix string_rep_test The patch fixes description (synopsis is at the end of the description) and fixes lower boundary for `n`, with `n` equal to zero assertion calculates negative number in right part of expression. Follows up #124 --- tests/lapi/string_rep_test.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/lapi/string_rep_test.lua b/tests/lapi/string_rep_test.lua index 08070e1..36af220 100644 --- a/tests/lapi/string_rep_test.lua +++ b/tests/lapi/string_rep_test.lua @@ -5,10 +5,10 @@ Copyright (c) 2023-2025, Sergey Bronnikov. 6.4 – String Manipulation https://www.lua.org/manual/5.3/manual.html#6.4 -Synopsis: string.rep(s, n [, sep]) - read overflow in 'l_strcmp', https://github.com/lua/lua/commit/f623b969325be736297bc1dff48e763c08778243 + +Synopsis: string.rep(s, n [, sep]) ]] local luzer = require("luzer") @@ -18,7 +18,7 @@ local function TestOneInput(buf, _size) local fdp = luzer.FuzzedDataProvider(buf) os.setlocale(test_lib.random_locale(fdp), "all") -- Huge length leads to slow units. - local n = fdp:consume_integer(0, test_lib.MAX_STR_LEN) + local n = fdp:consume_integer(1, test_lib.MAX_STR_LEN) local s = fdp:consume_string(test_lib.MAX_STR_LEN) local sep = fdp:consume_string(test_lib.MAX_STR_LEN) local len = string.len(string.rep(s, n, sep)) From b86cd6527067a1774a2992d4151c0fa67a42a579 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Fri, 1 Aug 2025 13:32:50 +0300 Subject: [PATCH 5/8] tests/lapi: fix formatting --- tests/lapi/builtin_pairs_test.lua | 2 +- tests/lapi/os_setlocale_test.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lapi/builtin_pairs_test.lua b/tests/lapi/builtin_pairs_test.lua index 00b4120..2d53b1f 100644 --- a/tests/lapi/builtin_pairs_test.lua +++ b/tests/lapi/builtin_pairs_test.lua @@ -28,7 +28,7 @@ local function TestOneInput(buf) local MAX_N = 1000 local count = fdp:consume_integer(0, MAX_N) local tbl = fdp:consume_integers(test_lib.MIN_INT, test_lib.MAX_INT, count) - -- Use string keys to activate hash part of the table. + -- Use string keys to activate hash part of the table. tbl.a = fdp:consume_string(test_lib.MAX_STR_LEN) tbl.b = fdp:consume_string(test_lib.MAX_STR_LEN) for key, value in pairs(tbl) do diff --git a/tests/lapi/os_setlocale_test.lua b/tests/lapi/os_setlocale_test.lua index 3a8c4cd..492226b 100644 --- a/tests/lapi/os_setlocale_test.lua +++ b/tests/lapi/os_setlocale_test.lua @@ -19,7 +19,7 @@ local function TestOneInput(buf) }) local locale_string = os.setlocale(locale, category) assert(type(locale_string) == "string" or - locale_string == nil) + locale_string == nil) end local args = { From 2d00c57f961d5f231268971cc46a1b9fb1ff3de1 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Wed, 6 Aug 2025 18:08:02 +0300 Subject: [PATCH 6/8] tests/lapi: cache locales in random_locale() The patch changes function `random_locale()`, so it builds a table with locales only once on the first execution and then returns a cached table. --- tests/lapi/lib.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/lapi/lib.lua b/tests/lapi/lib.lua index c4bb890..973ee22 100644 --- a/tests/lapi/lib.lua +++ b/tests/lapi/lib.lua @@ -86,9 +86,14 @@ local function approx_equal(a, b, epsilon) return abs(a - b) <= ((abs(a) < abs(b) and abs(b) or abs(a)) * epsilon) end +local locales + local function random_locale(fdp) - local locales = {} + if locales then + return fdp:oneof(locales) + end local locale_it = io.popen("locale -a"):read("*a"):gmatch("([^\n]*)\n?") + locales = {} for locale in locale_it do table.insert(locales, locale) end From 35b6dc84014ac53c32459819525aaad7e2e60d8a Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Wed, 6 Aug 2025 21:47:11 +0300 Subject: [PATCH 7/8] tests/lapi: add table.clear test The patch adds a test for `table.clear()` function that is present in LuaJIT. Follows up the commit ee032e778059 ("tests/lapi: add table tests"). Follows up #142 --- tests/lapi/table_clear_test.lua | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/lapi/table_clear_test.lua diff --git a/tests/lapi/table_clear_test.lua b/tests/lapi/table_clear_test.lua new file mode 100644 index 0000000..78d9bca --- /dev/null +++ b/tests/lapi/table_clear_test.lua @@ -0,0 +1,46 @@ +--[[ +SPDX-License-Identifier: ISC +Copyright (c) 2023-2025, Sergey Bronnikov. + +Double-emitting of IR_NEWREF for the same key on the snap replay, +https://github.com/LuaJIT/LuaJIT/issues/1128 + +X86/X64 load fusion conflict detection doesn't detect table.clear, +https://github.com/LuaJIT/LuaJIT/issues/1117 + +Problem of HREFK with table.clear, +https://github.com/LuaJIT/LuaJIT/issues/792 + +Add support for freeing memory manually, +https://github.com/LuaJIT/LuaJIT/issues/620 + +Synopsis: table.clear(tbl) +]] + +local luzer = require("luzer") +local test_lib = require("lib") + +if test_lib.lua_version() ~= "LuaJIT" then + print("Unsupported version.") + os.exit(0) +end + +local table_clear = require("table.clear") + +local function TestOneInput(buf) + local fdp = luzer.FuzzedDataProvider(buf) + local count = fdp:consume_integer(0, test_lib.MAX_INT64) + local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count) + table_clear(tbl) + -- Make sure the table is empty. + local n_items = 0 + for _ in pairs(tbl) do + n_items = n_items + 1 + end + assert(n_items == 0) +end + +local args = { + artifact_prefix = "table_clear_", +} +luzer.Fuzz(TestOneInput, nil, args) From e616e6ff3e0606861b30406a4936b847dbe85613 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Fri, 8 Aug 2025 15:43:53 +0300 Subject: [PATCH 8/8] tests/lapi: update assertions in os tests The patch updates assertions for values returned by `os.date()` and `os.time()`. Follows up #141 --- tests/lapi/os_date_test.lua | 8 +++----- tests/lapi/os_time_test.lua | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/lapi/os_date_test.lua b/tests/lapi/os_date_test.lua index ac63eac..61a59b4 100644 --- a/tests/lapi/os_date_test.lua +++ b/tests/lapi/os_date_test.lua @@ -32,11 +32,9 @@ local function TestOneInput(buf) local err_handler = test_lib.err_handler(ignored_msgs) local ok, res = xpcall(os.date, err_handler, format, time) if not ok then return end - assert(type(res) == "string" or - type(res) == "table" or - -- Undocumented. - type(res) == "number" or - res == nil) + local type_check = type(res) == "string" or type(res) == "table" + local undocumented_type_check = type(res) == "number" or res == nil + assert(type_check or undocumented_type_check) end local args = { diff --git a/tests/lapi/os_time_test.lua b/tests/lapi/os_time_test.lua index 981ffed..8bab123 100644 --- a/tests/lapi/os_time_test.lua +++ b/tests/lapi/os_time_test.lua @@ -32,11 +32,9 @@ local function TestOneInput(buf) local err_handler = test_lib.err_handler(ignored_msgs) local ok, res = xpcall(os.time, err_handler, time) if not ok then return end - io.stderr:write(type(res) .. "\n") - assert(type(res) == "number" or - type(res) == "table" or - -- Undocumented. - res == nil) + local type_check = type(res) == "number" or type(res) == "table" + local undocumented_type_check = res == nil + assert(type_check or undocumented_type_check) end local args = {