Reject unpaired surrogates in JsonWriter STRICT mode - #3121
Open
sushant-me wants to merge 1 commit into
Open
sushant-me wants to merge 1 commit into
sushant-me wants to merge 1 commit into
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
sushant-me
force-pushed
the
fix/jsonwriter-unpaired-surrogates
branch
from
September 15, 2026 04:45
4e519de to
77a9ba7
Compare
Author
|
@googlebot I signed it! |
JsonReader has rejected unpaired UTF-16 surrogates in STRICT mode since PR google#3116, but JsonWriter still writes them. That produces a document which this class's own documentation promises conforms to RFC 8259 but which no conforming parser can read back, and which is silently replaced by '?' when the document is encoded as UTF-8. Gson's own default output is therefore unreadable by Gson in STRICT mode. Validate the value on the write path the same way the read path does, so the two sides of the API agree on what a strict JSON string is. The check is limited to Strictness.STRICT so callers of the legacy permissive modes see no behaviour change. Adds writer-side tests mirroring the existing JsonReaderTest coverage; the writer previously had none.
sushant-me
force-pushed
the
fix/jsonwriter-unpaired-surrogates
branch
from
September 15, 2026 08:59
77a9ba7 to
9706389
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
JsonReaderrejects unpaired UTF-16 surrogate characters in strict mode (that was #3113 / #3116), butJsonWriterhas no equivalent validation, so the two sides of the API disagree about what a strict JSON string is.An unpaired surrogate in a Java
Stringhas no faithful JSON encoding: a JSON string is a sequence of Unicode characters (RFC 8259 section 7). Two consequences today, both silent:JsonWriterwithStrictness.STRICTwrites the value anyway, producing a document that its own Javadoc promises conforms to RFC 8259 but whichJsonReaderin the same strictness mode then refuses to read back. Gson's own default output is not readable by Gson.?, so data is silently lost.What this changes
JsonWriter.string(...)is the single sink for both names and values, so validating there coversvalue(String),name(String)and deferred names alike:validateStringmirrorsJsonReader.validateStringexactly, including the message, so a caller that catches one path understands the other.Scope
The check is limited to
Strictness.STRICT.LEGACY_STRICTandLENIENTare unchanged, so no existing caller sees different output. That mirrors how the read side was introduced, and is why this is not a behaviour change for anyone who did not already opt into strict mode.Tests
Adds the writer-side coverage that never existed:
testStrictModeRejectsUnpairedSurrogates— lone high, lone low, embedded, and reversed pair.testStrictModeRejectsUnpairedSurrogateInName— the name path (rejection surfaces when the entry is completed, because names are written lazily).testStrictModeAllowsPairedSurrogates— a valid pair is written and then read back in strict mode, which is the round-trip property the bug broke.testNonStrictModesStillAllowUnpairedSurrogates— pins the legacy behaviour so it cannot regress accidentally.mvn -pl gson testpasses: 4671 tests, 0 failures, 0 errors.