aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThijs Schreijer <thijs@thijsschreijer.nl>2026-08-29 17:19:19 +0200
committerThijs Schreijer <thijs@thijsschreijer.nl>2026-08-29 17:22:41 +0200
commit827ae20771d34912a8f79b50dc68e6430945b9eb (patch)
tree34357203cc3431096167a7bf6feb4ff2dca1ee8b
parent8cbbce56e64c84b53593c815f6dcdd9214897b74 (diff)
downloadluasocket-827ae20771d34912a8f79b50dc68e6430945b9eb.tar.gz
luasocket-827ae20771d34912a8f79b50dc68e6430945b9eb.tar.bz2
luasocket-827ae20771d34912a8f79b50dc68e6430945b9eb.zip
fix(receive): guard numeric pattern against size_t overflow on cast
Same class of bug as the maxsize cast: a double larger than SIZE_MAX cast to size_t is undefined behavior. Bound-check the numeric receive pattern before the cast, and cover it with a test.
-rw-r--r--src/buffer.c3
-rw-r--r--test/testclnt.lua6
2 files changed, 6 insertions, 3 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 5f06fc1..3d48a09 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -125,7 +125,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
125 /* ---- validation: must precede timeout_markstart() and any I/O ---- */ 125 /* ---- validation: must precede timeout_markstart() and any I/O ---- */
126 if (numeric) { 126 if (numeric) {
127 double n = lua_tonumber(L, 2); 127 double n = lua_tonumber(L, 2);
128 luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); 128 luaL_argcheck(L, n >= 0 && n < (lua_Number) ((size_t) -1), 2,
129 "invalid receive pattern");
129 wanted = (size_t) n; 130 wanted = (size_t) n;
130 } else { 131 } else {
131 const char *p = luaL_optstring(L, 2, "*l"); 132 const char *p = luaL_optstring(L, 2, "*l");
diff --git a/test/testclnt.lua b/test/testclnt.lua
index ec154ea..ee64d3a 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -642,14 +642,16 @@ function test_maxsize()
642 assert(not ok, "A6 failed: wanted > maxsize should raise") 642 assert(not ok, "A6 failed: wanted > maxsize should raise")
643 ok = pcall(data.receive, data, "*l", nil, math.huge) 643 ok = pcall(data.receive, data, "*l", nil, math.huge)
644 assert(not ok, "A7 failed: maxsize=math.huge should raise (size_t overflow)") 644 assert(not ok, "A7 failed: maxsize=math.huge should raise (size_t overflow)")
645 ok = pcall(data.receive, data, math.huge)
646 assert(not ok, "A8 failed: wanted=math.huge should raise (size_t overflow)")
645 data:settimeout(0.1) 647 data:settimeout(0.1)
646 ok = pcall(data.receive, data, 50, nil, 100) 648 ok = pcall(data.receive, data, 50, nil, 100)
647 assert(ok, "A8 failed: wanted <= maxsize should not raise") 649 assert(ok, "A9 failed: wanted <= maxsize should not raise")
648 data:settimeout(-1) 650 data:settimeout(-1)
649 remote [[ data:send('intact\n') ]] 651 remote [[ data:send('intact\n') ]]
650 local line, err = data:receive("*l", nil, 100) 652 local line, err = data:receive("*l", nil, 100)
651 assert(line == "intact", 653 assert(line == "intact",
652 "A9 failed: socket touched by a failed argcheck (err=" .. 654 "A10 failed: socket touched by a failed argcheck (err=" ..
653 tostring(err) .. ")") 655 tostring(err) .. ")")
654 pass("ok") 656 pass("ok")
655 657