Skip to content

fix: collect long-text results one at a time, so a long line no longer overflows the stack - #2248

Merged
cevheri merged 6 commits into
mainfrom
fix/long-text-argument-spreads
Nov 4, 2026
Merged

cevheri merged 6 commits into
mainfrom
fix/long-text-argument-spreads

Conversation

@cevheri

@cevheri cevheri commented Nov 4, 2026

Copy link
Copy Markdown
Member

Closes D453. A long user text could overflow the stack where a reader spread a text-sized array into push(...): the etcd lexer, the Qdrant request reader, the Cypher completion tokens and the SQL scope reader. Through POST /api/db/statement/analyze under Node 24, etcd ; x 130,000 and a Qdrant vector of 130,000 numbers answered 500 Maximum call stack size exceeded; they now answer 200, and etcd ; x 1,000,000 answers in about 300 ms.

Each fix replaces the spread with a loop; output and order are unchanged, and every new test failed before its fix (including a Node child process, since Bun's stack is deeper). The spread sites judged unreachable by a user text are listed in the backlog entry's resolution. Two related findings are filed: the etcd lexer's memory on one very long line, and a Redis argument spread.

Gate set green, coverage 100%.

@codecov

codecov Bot commented Nov 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

… of ; or ( is refused

A line of ; or ( places one refusal per character, and splitWords added a line's refusals to the text's list as the arguments of one call, which overflows the stack past the arguments a runtime takes: isDestructiveNonSqlQuery raised RangeError at 700,000 such characters under Bun 1.4.4 and at 130,000 under Node 24.22.1, so the web editor's gate and the provider's own guard failed on the line, and POST /api/db/statement/analyze on the production server answered it 500. lexLogicalLine collected its refusals the same way. Both now push them in a loop, and the lexer's output is unchanged.

tests/unit/db/etcd/long-line-runtimes.test.ts drives a 1,000,000-character line of ; and one of ( through the gate and the provider's guard under Bun and in a Node child, and each is refused at its first character, as a line of one is. The lexer and route tests hold the same lines. Backlog entry D453 is removed.
…options key

refuseOptions pushed a list's items onto its walk as the arguments of one call. The console admits a list of 262,144 numbers, and that walk overflowed the stack at 130,000 under Node 24.22.1, so the gate, the statement analysis and the provider, which all run it first, failed on a long vector query under Node, and POST /api/db/statement/analyze on the production server answered it 500. Bun 1.4.4 took the whole bound. The walk now pushes the items in a loop, in the same order.

tests/unit/db/qdrant/request-runtimes.test.ts gains a vector of the console's 262,144 numbers, accepted with the same body on Bun and on Node.
cypherCompletionContext added each line's tokens to its list as the arguments of one call, so a line of one token per character overflowed the stack: at 700,000 under Bun 1.4.4 and at 130,000 under Node 24.22.1, the V8 of Chrome and Edge. The tokens are now pushed in a loop, and a line of 1,000,000 reads to the context its end is in.
statementScope added a level's sources and its CTE names to its lists as the arguments of one call, so a long enough FROM list or WITH list overflowed the stack in the SQL completion provider: at 700,000 under Bun 1.4.4 and at 130,000 under Node 24.22.1, the V8 of Chrome and Edge. Both are now pushed in a loop, and a list of 1,000,000 names every item.
Under Bun 1.4.4 the original code passed 600,000 and overflowed from 650,000; the comments named Node's 130,000 instead.
…Redis argument spread

D456: a line of ; or ( grows the Node heap by several hundred bytes per character and aborts the process at 10,000,000 characters, under the body limit. D457: runCommand spreads a command's words into callBuffer and answers the overflow as a Redis error.
@cevheri
cevheri force-pushed the fix/long-text-argument-spreads branch from 1bc285b to f504b13 Compare November 4, 2026 22:52
@sonarqubecloud

sonarqubecloud Bot commented Nov 4, 2026

Copy link
Copy Markdown

@cevheri
cevheri merged commit 5b67914 into main Nov 4, 2026
39 checks passed
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.

1 participant