Skip to content

Commit f504b13

Browse files
committed
docs(backlog): record the etcd lexer's memory on a long line and the 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.
1 parent 5d03f86 commit f504b13

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

‎docs/BACKLOG.md‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ None of it is a GitHub issue.
2828
**Sections**
2929

3030
- [SQL statement reading](#sql-statement-reading) — S2-S11 · 8
31-
- [Drivers and connections](#drivers-and-connections) — D1-D455, U17 · 334
31+
- [Drivers and connections](#drivers-and-connections) — D1-D457, U17 · 336
3232
- [Value interpolation](#value-interpolation) — V1
3333
- [Row editing](#row-editing) — R1–R3 · 3
3434
- [Studio UI and query execution](#studio-ui-and-query-execution) — X2-X26, U2-U202 · 188
@@ -4464,6 +4464,26 @@ Found 2026-11-04 by the review of the change that moved that refusal into `resol
44644464

44654465
**Done when:** the five checks are gone, the five mocked cases are removed or moved onto the real `resolveConnection`, and `bun run coverage:check` passes.
44664466

4467+
### D456. The etcd lexer grows the heap by several hundred bytes per character of a line of `;` or `(`, so a line at the body limit aborts a Node process
4468+
4469+
`splitWords` and `lexLogicalLine` in `src/lib/db/providers/keyvalue/etcd/lexer.ts` place one refusal per `;` or `(` and keep every one, with its tokens, until the line is read.
4470+
Measured on 2026-11-05 with `isDestructiveNonSqlQuery(text, "etcd")` bundled for Node 24.22.1 (default heap limit 4,288 MiB): 1,000,000 characters grew RSS by 654 MiB in 386 ms, 3,000,000 by 1,651 MiB in 1,024 ms, 7,000,000 by 3,790 MiB in 4,467 ms, and 10,000,000 aborted the process with `FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory`; a line of `(` measured the same.
4471+
Ten million characters fit under the 10,485,760-byte body limit of X19, so one request to a route that reads the text, such as `POST /api/db/statement/analyze`, can carry it; the route itself was not driven at that size.
4472+
The answer at every size that completed was right (`false`); only the cost is wrong.
4473+
Found 2026-11-05 by the review of the change that collected the etcd lexer's refusals one at a time.
4474+
4475+
**Done when:** the lexer's memory for a line of `;` or `(` no longer grows in proportion to the refusals it places, and a test under Node reads a 10,000,000-character line of each through `isDestructiveNonSqlQuery` without the process aborting.
4476+
4477+
### D457. A Redis command of about 120,000 words or more answers `Redis error: Maximum call stack size exceeded`
4478+
4479+
`runCommand` in `src/lib/db/providers/keyvalue/redis.ts` sends a command as `callBuffer(command, ...args)`, an argument spread of one element per word, and its catch answers every error as `Redis error: <message>`, so a stack overflow at the call site reads as the server's refusal.
4480+
The plain line and the JSON form (`{"command": ..., "args": [...]}`) both reach it, and nothing bounds the word count before it.
4481+
Measured on 2026-11-05 by calling the provider's `executeRedisCommand` with `DEL k k ...` over a stub client whose `callBuffer` takes rest arguments, as ioredis's does: under Node 24.22.1, 110,000 words ran and 120,000 answered `QueryError: Redis error: Maximum call stack size exceeded`; under Bun 1.4.4, 130,000 ran and 1,000,000 answered the same.
4482+
The agent path's `client.call(argv[0], ...argv.slice(1))` has the same shape, but `readRedisAgentStatement` admits a head, one key and at most two option words, and `FUNCTION LOAD`'s `call(unit.name, ...unit.arguments, ...)` spreads the fixed `LOAD REPLACE`, so neither is reachable with a long list.
4483+
Found 2026-11-05 by the review of the change that collected the etcd lexer's refusals one at a time.
4484+
4485+
**Done when:** a Redis command with more words than a runtime takes arguments is either sent without an argument spread or refused before the send with a sentence that names the word count, and a test drives 1,000,000 words through the plain and the JSON form.
4486+
44674487
## Value interpolation
44684488

44694489
### V1. Query history records the placeholders, not the values that were bound

0 commit comments

Comments
 (0)