perf(memory-safety): scan JSON structure by char code

The structure scan added to the daemon's receive path cost 4x more than the
JSON.parse it guards: it indexed the string per character, allocating a
one-character string for every byte, and walked string bodies one byte at a
time even though a string's contents carry no structure.

Read char codes instead, and skip each string body to its closing quote in
one indexOf. Two cursors keep that skip linear: a monotonic escape cursor so
backslash lookups never rescan, and a hoisted closing-quote index that is
re-derived only when the escape cursor passes it. Deriving the closing quote
inside the escape loop instead would rescan the tail once per escape, which
is quadratic on a payload carrying escaped text -- 2.3s on a 4 MB body.

Same input, same verdict: 505,720 differential cases against the previous
char-by-char implementation -- 240,000 randomized over a structural / escape /
unicode alphabet under four limit sets, plus every string up to length 5 over
{ } [ ] , : " \ a -- produce identical results, including the thrown
resource and limit. Dropping the closing-quote refresh reintroduces
mismatches, so the coverage is not vacuous.

20k scans of a 2 KiB message: 286ms -> 5.3ms. The guard now costs less than
the parse it protects, which takes the daemon's fragmented-feed overhead from
2.95x down to 1.44x. On a 4 MB escape-dense body: 14.0ms -> 0.9ms.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-07-26 22:41:37 -07:00
co-authored by Orca
parent 2d5fd8def8
commit c01d5e167a
2 changed files with 117 additions and 28 deletions
@@ -37,4 +37,74 @@ describe('JSON text structure admission', () => {
})
).not.toThrow()
})
// The scan skips string bodies wholesale, so a backslash run that ends a string on an even
// count — and one that escapes the quote on an odd count — must resolve the same way.
it.each([
['{"value":"\\\\"}', 'even backslash run closes the string'],
['{"value":"\\\\\\\\"}', 'longer even backslash run closes the string'],
['{"value":"\\""}', 'escaped quote does not close the string'],
['{"a":"}","b":"]"}', 'structural characters inside adjacent strings'],
['{"emoji":"💥{[,:"}', 'astral-plane characters inside a string']
])('tracks string boundaries through %s', (content) => {
expect(() =>
assertJsonTextStructureWithinLimits(content, {
structuralTokens: 1_000,
nestingDepth: 8
})
).not.toThrow()
})
it('stops scanning at an unterminated string instead of counting its contents', () => {
expect(() =>
assertJsonTextStructureWithinLimits('{"value":"[[[[[[[[[[', {
structuralTokens: 2,
nestingDepth: 1
})
).not.toThrow()
})
it('scans an escape-dense string body in linear time', () => {
// Why: a frame carrying a text file is one huge escaped string. Rescanning for the closing
// quote once per escape is quadratic and stalls the receive loop for seconds at 4 MB.
const body = `${'a'.repeat(63)}\\n`.repeat(66_000)
const frame = `{"jsonrpc":"2.0","params":{"data":"${body}"}}`
expect(frame.length).toBeGreaterThan(4_000_000)
const startedAt = performance.now()
assertJsonTextStructureWithinLimits(frame, {
structuralTokens: 1_000_000,
nestingDepth: 128
})
// Generous versus the ~1ms linear scan, but far under the ~2.5s the quadratic path takes.
expect(performance.now() - startedAt).toBeLessThan(500)
})
it.each([
['{"a":"x\\\\","b":1}', 'a body ending in an escaped backslash'],
['{"a":"\\\\\\"}","b":2}', 'an escaped backslash before an escaped quote'],
['{"a":"\\"\\"\\"","b":3}', 'consecutive escaped quotes'],
['{"a":"\\n\\n\\n","b":4}', 'repeated short escapes']
])('finds the true string end past %s', (content) => {
// Why: the scan advances a cursor past each escape and only rescans for the closing quote
// once the cursor passes it — a stale quote index would end the string early and count
// the remaining body as structure.
expect(() =>
assertJsonTextStructureWithinLimits(content, {
structuralTokens: 6,
nestingDepth: 4
})
).not.toThrow()
})
it('rejects a deeply nested line before it becomes an object graph', () => {
const depth = 1_024
expect(() =>
assertJsonTextStructureWithinLimits(`${'['.repeat(depth)}${']'.repeat(depth)}`, {
structuralTokens: 1_000_000,
nestingDepth: 128
})
).toThrowError(new JsonTextStructureCapacityError('nestingDepth', 128))
})
})
@@ -17,6 +17,14 @@ export class JsonTextStructureCapacityError extends Error {
}
}
const QUOTE = 0x22
const COMMA = 0x2c
const COLON = 0x3a
const OPEN_BRACKET = 0x5b
const CLOSE_BRACKET = 0x5d
const OPEN_BRACE = 0x7b
const CLOSE_BRACE = 0x7d
export function assertJsonTextStructureWithinLimits(
content: string,
limits: JsonTextStructureLimits
@@ -25,38 +33,60 @@ export function assertJsonTextStructureWithinLimits(
assertLimit(limits.nestingDepth)
let structuralTokens = 0
let depth = 0
let inString = false
let escaped = false
// Why: this runs on the daemon's hot receive path, so the scan reads char codes and skips
// string bodies wholesale. A monotonic escape cursor keeps the lookups O(n) overall.
let nextEscape = content.indexOf('\\')
for (let index = 0; index < content.length; index += 1) {
const character = content[index]
if (inString) {
if (escaped) {
escaped = false
} else if (character === '\\') {
escaped = true
} else if (character === '"') {
inString = false
const code = content.charCodeAt(index)
if (code === QUOTE) {
// String contents carry no structure; jump to the closing quote rather than
// stepping through every byte of a large payload.
let cursor = index + 1
// Why: hoisted so an escape-dense body rescans the tail once per *skipped* quote rather
// than once per escape — the latter is quadratic on a payload carrying escaped text.
let closing = content.indexOf('"', cursor)
for (;;) {
if (closing < 0) {
return
}
if (nextEscape >= 0 && nextEscape < cursor) {
nextEscape = content.indexOf('\\', cursor)
}
if (nextEscape < 0 || nextEscape > closing) {
index = closing
break
}
cursor = nextEscape + 2
if (cursor > closing) {
closing = content.indexOf('"', cursor)
}
}
continue
}
if (character === '"') {
inString = true
continue
}
if (!isStructuralToken(character)) {
if (
code !== OPEN_BRACE &&
code !== CLOSE_BRACE &&
code !== OPEN_BRACKET &&
code !== CLOSE_BRACKET &&
code !== COMMA &&
code !== COLON
) {
continue
}
structuralTokens += 1
if (structuralTokens > limits.structuralTokens) {
throw new JsonTextStructureCapacityError('structuralTokens', limits.structuralTokens)
}
if (character === '{' || character === '[') {
if (code === OPEN_BRACE || code === OPEN_BRACKET) {
depth += 1
if (depth > limits.nestingDepth) {
throw new JsonTextStructureCapacityError('nestingDepth', limits.nestingDepth)
}
} else if (character === '}' || character === ']') {
} else if (code === CLOSE_BRACE || code === CLOSE_BRACKET) {
depth = Math.max(0, depth - 1)
}
}
@@ -67,14 +97,3 @@ function assertLimit(value: number): void {
throw new RangeError('JSON structure limits must be non-negative safe integers')
}
}
function isStructuralToken(character: string | undefined): boolean {
return (
character === '{' ||
character === '}' ||
character === '[' ||
character === ']' ||
character === ',' ||
character === ':'
)
}