Skip to content

fix(string.rep): allocate proportionally to result, not repeat count#376

Open
smn wants to merge 1 commit into
tv-labs:mainfrom
smn:string-rep-allocation
Open

fix(string.rep): allocate proportionally to result, not repeat count#376
smn wants to merge 1 commit into
tv-labs:mainfrom
smn:string-rep-allocation

Conversation

@smn

@smn smn commented Jun 20, 2026

Copy link
Copy Markdown

Fixes #373

full disclosure: Claude helped here

`string.rep` built its result with `Enum.map_join(1..n, sep, fn _ -> str
end)`, which materializes an n-element list (plus its iolist) as transient
garbage. For a large repeat count that intermediate is tens of times the
size of the result itself, so producing an otherwise-modest string spikes
the process heap.

This is what issue tv-labs#373 observes: returning a 16 MB string built by
`string.rep` through `Lua.call_function!/3` left ~1 GB of reachable garbage
(call_function returns before the next GC sweeps it), and on a heap-limited
process the spike trips `max_heap_size` and kills it. The same spike occurs
on the `Lua.eval!/2` path; it is just masked there because the surrounding
decode/wrap work triggers a GC before the caller measures.

Build the binary in a single pass with `:binary.copy/2` so allocation is
proportional to the output. The pre-build `Limits.check_string_size!` guard
is unchanged, so oversized requests still raise catchably without
allocating.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NvaxgWQcfipbKBaU4KxnuW
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lua.call_function!/3 allocates ~50× the payload when a Lua function returns a large string

2 participants