IO receive effects eagerly allocate the caller-supplied max and abort the whole process (_exit) on allocation failure
Summary
The receive effects allocate the full caller-supplied max up front and treat allocation failure as fatal _exit(1), not as a catchable Fail:
bend2/effs/tcp_recv.c:22-23,file_read.c,file_read_bytes.c,udp_recv_from.c,udp_poll.c(same pattern):w->made = f[1] < INT32_MAX ? (intptr_t)f[1] : INT32_MAX; w->data = io_mem(malloc((size_t)w->made + 1));—f[1]is the raw U32 max, so the buffer is sized entirely from caller input before a single byte is read.io_mem→err_fail→_exit(1): allocation failure kills every spawned computation and is never observable asResult.Fail.comp.ts:5744(chan_open) mallocsroom*8on the same fatal path.- JS lane:
tcp_recv.js/udp_recv_from.js/udp_poll.jsdonew Uint8Array(Math.max(Number(max), 1))with no clamp (a clamp PR is separately proposed);file_read.jsclamps.
Impact
File.read(f, 4294967295n) or TCP.recv(sock, 4294967295n) — plain bend, no @unsafe — asks the OS for a 2-4 GiB buffer. On this audit's dev machine (macOS, overcommit) the allocation lazily succeeded and the program survived, so no end-to-end crash was reproduced here; but on hosts with strict overcommit / memory limits (typical Linux containers) the process aborts uncatchably, and when max derives from network input (Content-Length pattern) this is a remote one-request kill switch per connection. Note the JS FFI passes the length as u32 (recv:ipUi>I), so there is no sign bug — the issue is purely eager allocation of untrusted sizes.
Suggested fix
Grow the receive buffer on demand (recv loop), or return io_fail(ENOMEM) instead of err_fail so allocation failure surfaces as Fail{...}.
Version / system
- bend 2.0.5 (main @ e6676b0)
- Darwin arm64; C analysis by reading the kit spliced into emitted programs
Source: HigherOrderCO/Bend