Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lang/c++/impl/json/JsonIO.hh
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,13 @@ class AVRO_DECL JsonGenerator {
value <<= 6;
value |= *p & 0x3f;
}
if (value >= 0xd800 && value <= 0xdfff) {
// Surrogate code points are ill-formed in UTF-8 and
// cannot be represented in JSON; emitting them here
// produces a lone \u surrogate, matching what the
// decoder already rejects.
throw Exception("Invalid UTF-8 sequence");
}
escapeUnicode(value);
}
} else {
Expand Down
9 changes: 9 additions & 0 deletions lang/c++/test/JsonTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,14 @@ static void testLoneLowSurrogate() {
BOOST_CHECK_THROW(loadEntity(R"("\udfff")").stringValue(), Exception);
}

// A string whose bytes encode a UTF-16 surrogate code point (U+D800..U+DFFF)
// is ill-formed UTF-8 and cannot be represented in JSON. Encoding it must be
// rejected rather than emitting a lone \u surrogate.
static void testEncodeSurrogate() {
BOOST_CHECK_THROW(loadEntity("\"\xed\xa0\x80\"").toString(), Exception);
BOOST_CHECK_THROW(loadEntity("\"\xed\xbf\xbf\"").toString(), Exception);
}

} // namespace json
} // namespace avro

Expand Down Expand Up @@ -218,6 +226,7 @@ init_unit_test_suite(int /* argc */, char * /* argv */[]) {
ts->add(BOOST_TEST_CASE(&avro::json::testObject2));

ts->add(BOOST_TEST_CASE(&avro::json::testLoneLowSurrogate));
ts->add(BOOST_TEST_CASE(&avro::json::testEncodeSurrogate));

return ts;
}