diff options
| author | Thijs Schreijer <thijs@thijsschreijer.nl> | 2026-08-29 17:19:19 +0200 |
|---|---|---|
| committer | Thijs Schreijer <thijs@thijsschreijer.nl> | 2026-08-29 17:22:41 +0200 |
| commit | 827ae20771d34912a8f79b50dc68e6430945b9eb (patch) | |
| tree | 34357203cc3431096167a7bf6feb4ff2dca1ee8b | |
| parent | 8cbbce56e64c84b53593c815f6dcdd9214897b74 (diff) | |
| download | luasocket-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.c | 3 | ||||
| -rw-r--r-- | test/testclnt.lua | 6 |
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 | ||
