gin/render
okxint 3498e1cdbc fix(render): encode non-BMP characters as UTF-16 surrogate pairs in AsciiJSON
AsciiJSON.Render used fmt.Appendf(buf, "\\u%04x", r) for all non-ASCII
runes. The %04x format is a *minimum* width, not a fixed width, so runes
above U+FFFF (emoji, musical symbols, supplementary CJK, etc.) produce a
5-digit escape like \u1f600. JSON \u escapes are always exactly 4 hex
digits (RFC 8259 §7), so a decoder reads the first 4 digits as a
different character and treats the remaining digit(s) as literal text.
The output is still syntactically valid JSON, which makes the corruption
easy to miss — values silently fail to round-trip.

Fix: detect runes > U+FFFF and split them into a UTF-16 surrogate pair
(\uHHHH\uLLLL) before writing the escape. BMP characters continue to use
the single-escape path unchanged.

Add TestRenderAsciiJSONNonBMP to verify correct surrogate-pair encoding
and full round-trip fidelity for 😀 (U+1F600), 𝄞 (U+1D11E), and 𠀀 (U+20000).

Fixes #4688

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-09-02 12:29:43 +05:30
..