Skip to content

Commit 6f31297

Browse files
Mike PallBuristan
authored andcommitted
Prevent sanitizer warnings for lj_tab_new*() and table.new().
Reported by Sergey Bronnikov. (cherry picked from commit 8f421c8) The Undefined Behaviour Sanitizer [1] produces a warning because the function `lua_createtable()` takes signed integer arguments, but the `lj_tab_new_ah()` was not properly validating or converting these signed values before using them in unsigned arithmetic. The fix changes the signature of `lj_tab_new_ah()` to accept uint32_t directly, and adjusts `lua_createtable()` to cast the incoming signed int values to uint32_t before passing them. [1]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html Sergey Bronnikov: * added the description and the test for the problem Part of tarantool/tarantool#12480 Reviewed-by: Evgeniy Temirgaleev <e.temirgaleev@tarantool.org> Reviewed-by: Sergey Kaplun <skaplun@tarantool.org> Signed-off-by: Sergey Kaplun <skaplun@tarantool.org>
1 parent 3466fb1 commit 6f31297

4 files changed

Lines changed: 34 additions & 4 deletions

File tree

src/lj_api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
746746
LUA_API void lua_createtable(lua_State *L, int narray, int nrec)
747747
{
748748
lj_gc_check(L);
749-
settabV(L, L->top, lj_tab_new_ah(L, narray, nrec));
749+
settabV(L, L->top, lj_tab_new_ah(L, (uint32_t)narray, (uint32_t)nrec));
750750
incr_top(L);
751751
}
752752

src/lj_tab.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,9 @@ GCtab *lj_tab_new(lua_State *L, uint32_t asize, uint32_t hbits)
165165
}
166166

167167
/* The API of this function conforms to lua_createtable(). */
168-
GCtab *lj_tab_new_ah(lua_State *L, int32_t a, int32_t h)
168+
GCtab *lj_tab_new_ah(lua_State *L, uint32_t a, uint32_t h)
169169
{
170-
return lj_tab_new(L, (uint32_t)(a > 0 ? a+1 : 0), hsize2hbits(h));
170+
return lj_tab_new(L, a ? a+1 : 0, hsize2hbits(h));
171171
}
172172

173173
#if LJ_HASJIT

src/lj_tab.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static LJ_AINLINE uint32_t hashrot(uint32_t lo, uint32_t hi)
3434
#define hsize2hbits(s) ((s) ? ((s)==1 ? 1 : 1+lj_fls((uint32_t)((s)-1))) : 0)
3535

3636
LJ_FUNCA GCtab *lj_tab_new(lua_State *L, uint32_t asize, uint32_t hbits);
37-
LJ_FUNC GCtab *lj_tab_new_ah(lua_State *L, int32_t a, int32_t h);
37+
LJ_FUNC GCtab *lj_tab_new_ah(lua_State *L, uint32_t a, uint32_t h);
3838
#if LJ_HASJIT
3939
LJ_FUNC GCtab * LJ_FASTCALL lj_tab_new1(lua_State *L, uint32_t ahsize);
4040
#endif
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
local tap = require('tap')
2+
3+
-- The test file to demonstrate UBSan warning for `table.new()`
4+
-- with a minimal and maximum array and hash parts values.
5+
-- See also: https://github.com/LuaJIT/LuaJIT/issues/1458.
6+
local test = tap.test('lj-1458-ub-table-new')
7+
8+
local INT_MAX = 2 ^ 31 - 1
9+
local INT_MIN = -2 ^ 31
10+
11+
local table_sizes = {
12+
{ 0, INT_MIN },
13+
{ 0, INT_MAX },
14+
{ INT_MIN, 0 },
15+
{ INT_MAX, 0 },
16+
}
17+
18+
test:plan(#table_sizes * 2)
19+
20+
local table_new = require('table.new')
21+
22+
for _, case in ipairs(table_sizes) do
23+
local apart, hpart = unpack(case)
24+
local ok, err = pcall(table_new, apart, hpart)
25+
local message = ('table.new(%d, %d)'):format(apart, hpart)
26+
test:is(ok, false, message .. ' is ok')
27+
test:ok(err:match('table overflow'), message .. ' correct error message')
28+
end
29+
30+
test:done(true)

0 commit comments

Comments
 (0)