Skip to content

json: parser aborts on strings containing lone surrogates combined with escapes #4049

Description

@bobzhang

Summary

@json.parse crashes the process (an abort from a guard!, not a catchable ParseError) when a JSON string contains a raw lone trailing surrogate together with any escape sequence.

Minimal repro

A 5-code-unit JSON text: " U+DC00 \n "

test {
  let lone_low = String::from_array([(0xDC00).unsafe_to_char()])
  // aborts in StringView::sub (builtin/stringview.mbt guard!) instead of parsing:
  ignore(@json.parse("\"" + lone_low + "\\n\""))
}

Escape-free strings with the same lone surrogate parse fine (the fast path accepts them), so this is an internal inconsistency as well as a totality violation: a parser should either succeed or raise its documented ParseError, never abort.

Root cause

json/lex_string.mbt, ParseContext::lex_string_slow — the local flush helper slices the pending run with the checked ctx.input[start:end] (StringView::sub), which guard!-aborts when the code unit at a slice boundary is a trailing surrogate. The fast path in lex_string uses the bounds-check-only view(start_offset~, end_offset~) and therefore tolerates raw lone surrogates; only the slow path (taken whenever the string contains a backslash escape) crashes.

Affected targets

All backends — wasm-gc, js, and native (the abort is in shared library code; reproduced on all three).

Severity

High for robustness: any consumer parsing untrusted JSON text can be crashed (denial of service) by a short crafted input. Found by adversarial QuickCheck testing (the default Arbitrary String never generates lone surrogates, which is why existing property tests missed it).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions