summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-09-22 13:10:39 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-09-22 13:10:39 -0300
commitdeac067ed39a44c001599c0d15de09872496b2aa (patch)
treed7373651e7d54a8ca5ffa4841379a4d9149164aa
parent2ff34717227b8046b0fdcb96206f11f5e888664e (diff)
downloadlua-github-deac067ed39a44c001599c0d15de09872496b2aa.tar.gz
Avoid overflows when incrementing parameters in C
Any C function can receive maxinteger as an integer argument, and therefore cannot increment it without some care (e.g., doing unsigned arithmetic as the core does).
-rw-r--r--lauxlib.h8
-rw-r--r--lbaselib.c3
-rw-r--r--ltablib.c3
-rw-r--r--lutf8lib.c11
-rw-r--r--testes/nextvar.lua17
-rw-r--r--testes/utf8.lua6
6 files changed, 39 insertions, 9 deletions
diff --git a/lauxlib.h b/lauxlib.h
index 72f70e7d..6f9695e8 100644
--- a/lauxlib.h
+++ b/lauxlib.h
@@ -154,6 +154,14 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
+/*
+** Perform arithmetic operations on lua_Integer values with wrap-around
+** semantics, as the Lua core does.
+*/
+#define luaL_intop(op,v1,v2) \
+ ((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
+
+
/* push the value used to represent failure/error */
#define luaL_pushfail(L) lua_pushnil(L)
diff --git a/lbaselib.c b/lbaselib.c
index fd6687e6..912c4cc6 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -285,7 +285,8 @@ static int luaB_pairs (lua_State *L) {
** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
- lua_Integer i = luaL_checkinteger(L, 2) + 1;
+ lua_Integer i = luaL_checkinteger(L, 2);
+ i = luaL_intop(+, i, 1);
lua_pushinteger(L, i);
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
diff --git a/ltablib.c b/ltablib.c
index dbfe2509..868d78fd 100644
--- a/ltablib.c
+++ b/ltablib.c
@@ -59,8 +59,9 @@ static void checktab (lua_State *L, int arg, int what) {
static int tinsert (lua_State *L) {
- lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
lua_Integer pos; /* where to insert new element */
+ lua_Integer e = aux_getn(L, 1, TAB_RW);
+ e = luaL_intop(+, e, 1); /* first empty element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
pos = e; /* insert new element at the end */
diff --git a/lutf8lib.c b/lutf8lib.c
index 901d985f..e7bf098f 100644
--- a/lutf8lib.c
+++ b/lutf8lib.c
@@ -224,14 +224,11 @@ static int byteoffset (lua_State *L) {
static int iter_aux (lua_State *L, int strict) {
size_t len;
const char *s = luaL_checklstring(L, 1, &len);
- lua_Integer n = lua_tointeger(L, 2) - 1;
- if (n < 0) /* first iteration? */
- n = 0; /* start from here */
- else if (n < (lua_Integer)len) {
- n++; /* skip current byte */
- while (iscont(s + n)) n++; /* and its continuations */
+ lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
+ if (n < len) {
+ while (iscont(s + n)) n++; /* skip continuation bytes */
}
- if (n >= (lua_Integer)len)
+ if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
diff --git a/testes/nextvar.lua b/testes/nextvar.lua
index 076f6361..9e23e572 100644
--- a/testes/nextvar.lua
+++ b/testes/nextvar.lua
@@ -43,6 +43,14 @@ assert(i == 4)
assert(type(ipairs{}) == 'function' and ipairs{} == ipairs{})
+do -- overflow (must wrap-around)
+ local f = ipairs{}
+ local k, v = f({[math.mininteger] = 10}, math.maxinteger)
+ assert(k == math.mininteger and v == 10)
+ k, v = f({[math.mininteger] = 10}, k)
+ assert(k == nil)
+end
+
if not T then
(Message or print)
('\n >>> testC not active: skipping tests for table sizes <<<\n')
@@ -499,6 +507,15 @@ do -- testing table library with metamethods
end
+do -- testing overflow in table.insert (must wrap-around)
+
+ local t = setmetatable({},
+ {__len = function () return math.maxinteger end})
+ table.insert(t, 20)
+ local k, v = next(t)
+ assert(k == math.mininteger and v == 20)
+end
+
if not T then
(Message or print)
('\n >>> testC not active: skipping tests for table library on non-tables <<<\n')
diff --git a/testes/utf8.lua b/testes/utf8.lua
index 6010d1ad..461e223c 100644
--- a/testes/utf8.lua
+++ b/testes/utf8.lua
@@ -112,6 +112,12 @@ do
end
errorcodes("ab\xff")
errorcodes("\u{110000}")
+
+ -- calling interation function with invalid arguments
+ local f = utf8.codes("")
+ assert(f("", 2) == nil)
+ assert(f("", -1) == nil)
+ assert(f("", math.mininteger) == nil)
end
-- error in initial position for offset