Summary
json2.decode hangs forever (spinning, allocating without bound) on certain truncated inputs — specifically an unterminated array nested inside an object. The input is 10 bytes. This is worse than the deep-nesting crash (#TBD): a hang that consumes memory is a harder-to-detect denial of service than a clean crash.
Reproduction
import json2
fn main() {
_ := json2.decode[json2.Any]('{"a":[1,21') or { println('errored cleanly'); return }
println('parsed')
}
$ v run hang.v
... never returns; RSS climbs until OOM
A bare unterminated array ([1,) errors correctly with EOF: expected array value. The pathology is the array unterminated inside an object value — the parser fails to propagate EOF and loops.
Expected
Return a syntax error on EOF, as the bare-array case already does.
Impact
Ten-byte denial-of-service against anything decoding untrusted JSON. Truncated request bodies are a normal occurrence (dropped connections), so this is reachable without a malicious client.
Environment
V 0.5.2 5889122, Linux x86_64.
Note
Surfaced via adversarial fuzzing of a JSON-decoding library. Worked around downstream by rejecting unbalanced/truncated documents in a pre-scan. Filing on the fork to track for upstream.
Summary
json2.decodehangs forever (spinning, allocating without bound) on certain truncated inputs — specifically an unterminated array nested inside an object. The input is 10 bytes. This is worse than the deep-nesting crash (#TBD): a hang that consumes memory is a harder-to-detect denial of service than a clean crash.Reproduction
A bare unterminated array (
[1,) errors correctly withEOF: expected array value. The pathology is the array unterminated inside an object value — the parser fails to propagate EOF and loops.Expected
Return a syntax error on EOF, as the bare-array case already does.
Impact
Ten-byte denial-of-service against anything decoding untrusted JSON. Truncated request bodies are a normal occurrence (dropped connections), so this is reachable without a malicious client.
Environment
V 0.5.2 5889122, Linux x86_64.Note
Surfaced via adversarial fuzzing of a JSON-decoding library. Worked around downstream by rejecting unbalanced/truncated documents in a pre-scan. Filing on the fork to track for upstream.