mirror of
https://github.com/nlohmann/json.git
synced 2026-10-03 05:00:30 +00:00
Reject ill-formed UTF-8 in CBOR/UBJSON/BJData/BSON writers, accept it in MessagePack reader
to_cbor(), to_ubjson(), to_bjdata(), and to_bson() wrote a string or object
key with ill-formed UTF-8 byte for byte, but from_cbor()/from_ubjson()/
from_bjdata()/from_bson() reject such strings with parse_error.113 since
d19f7f5dc (#5185, not yet released): a value that serialized without error
could not be read back by the same library (#5651).
CBOR (RFC 8949 Section 5), UBJSON, BJData, and BSON all require text strings
and object keys/element names to be valid UTF-8, so their writers now
validate and throw type_error.316, like to_bon8() already does. For BSON,
the check runs in the size-computation pass, before any byte is written, the
same way the binary subtype check works. check_bon8_utf8() is renamed to
check_utf8() since it is now shared by all of these writers.
MessagePack's specification explicitly allows a str object to contain an
invalid byte sequence and expects a deserializer to hand the bytes back
unchanged, so its writer is unaffected and from_msgpack() (object keys
included) no longer validates UTF-8, restoring its pre-#5185 behavior.
dump() still rejects ill-formed UTF-8 with type_error.316 unless an error
handler is passed.
Docs: add the type_error.316 exception to to_cbor/to_ubjson/to_bjdata/to_bson,
document the writer-side check on the cbor/bson/ubjson/bjdata format pages,
and rewrite the MessagePack UTF-8 warning to describe the round-trip and
dump() behavior instead of a validation requirement the spec does not have.
Tests: add ill-formed value/key cases (invalid byte, truncated sequence,
encoded surrogate, overlong encoding) expecting type_error.316 to
unit-cbor.cpp, unit-ubjson.cpp, unit-bjdata.cpp, and unit-bson.cpp (which
also checks the output vector stays empty), and turn unit-msgpack.cpp's
former parse_error.113 ill-formed-UTF-8 tests into byte-for-byte round-trip
tests for both values and keys.
This text was written by Claude Code.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -56,6 +56,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
|
||||
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
|
||||
is false.
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is
|
||||
not valid UTF-8
|
||||
|
||||
## Complexity
|
||||
|
||||
@@ -89,4 +91,5 @@ Linear in the size of the JSON value `j`.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.11.0.
|
||||
- BJData version parameter (for draft3 binary encoding) added in version 3.12.0.
|
||||
- BJData version parameter (for draft3 binary encoding) added in version 3.12.0.
|
||||
- Throwing `type_error.316` for a string or object key that is not valid UTF-8 added in version 3.13.0.
|
||||
@@ -46,6 +46,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
- Throws [`out_of_range.415`](../../home/exceptions.md#jsonexceptionout_of_range415) if the subtype of a binary value
|
||||
exceeds 255, the maximum of the BSON binary subtype; example:
|
||||
`"subtype 70000 is too large for the BSON binary subtype (max 255)"`
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key is
|
||||
not valid UTF-8
|
||||
|
||||
## Complexity
|
||||
|
||||
@@ -82,3 +84,5 @@ pass before anything is written.
|
||||
- Added in version 3.4.0.
|
||||
- Linear in the size of `j`, and no longer limited by the call stack for deeply nested values, since version 3.13.0.
|
||||
- `out_of_range.415` is now detected before anything is written, like the other exceptions above, since version 3.13.0.
|
||||
- Throwing `type_error.316` for a string value or object key that is not valid UTF-8, detected before anything is
|
||||
written, added in version 3.13.0.
|
||||
|
||||
@@ -35,6 +35,11 @@ The exact mapping and its limitations are described on a [dedicated page](../../
|
||||
|
||||
Strong guarantee: if an exception is thrown, there are no changes in the JSON value.
|
||||
|
||||
## Exceptions
|
||||
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is
|
||||
not valid UTF-8
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear in the size of the JSON value `j`.
|
||||
@@ -68,3 +73,4 @@ Linear in the size of the JSON value `j`.
|
||||
|
||||
- Added in version 2.0.9.
|
||||
- Compact representation of floating-point numbers added in version 3.8.0.
|
||||
- Throwing `type_error.316` for a string or object key that is not valid UTF-8 added in version 3.13.0.
|
||||
|
||||
@@ -49,6 +49,8 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
|
||||
- Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size`
|
||||
is false.
|
||||
- Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is
|
||||
not valid UTF-8
|
||||
|
||||
## Complexity
|
||||
|
||||
@@ -82,3 +84,4 @@ Linear in the size of the JSON value `j`.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.1.0.
|
||||
- Throwing `type_error.316` for a string or object key that is not valid UTF-8 added in version 3.13.0.
|
||||
|
||||
@@ -63,6 +63,12 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
|
||||
- strings with more than 18446744073709551615 bytes, i.e., $2^{64}-1$ bytes (theoretical)
|
||||
|
||||
!!! warning "UTF-8 validation of string values and object keys"
|
||||
|
||||
BJData strings must use UTF-8 encoding. `to_bjdata()` validates the bytes of every string value and object key
|
||||
and throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for ill-formed UTF-8, so a
|
||||
value with such a string cannot be serialized in the first place.
|
||||
|
||||
!!! info "Unused BJData markers"
|
||||
|
||||
The following markers are not used in the conversion:
|
||||
@@ -208,6 +214,13 @@ The library maps BJData types to JSON value types as follows:
|
||||
|
||||
The mapping is **complete** in the sense that any BJData value can be converted to a JSON value.
|
||||
|
||||
!!! warning "UTF-8 validation of string values and object keys"
|
||||
|
||||
This library validates the bytes of every string value and object key at decode time and rejects ill-formed
|
||||
UTF-8 with a [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with
|
||||
`allow_exceptions` set to `false`, a discarded value), rather than only failing later when the resulting value
|
||||
is dumped.
|
||||
|
||||
!!! info "Round trips"
|
||||
|
||||
A value returned by [`from_bjdata`](../../api/basic_json/from_bjdata.md) can be serialized with
|
||||
|
||||
@@ -115,8 +115,12 @@ The library maps BSON record types to JSON value types as follows:
|
||||
bytes of every such string at decode time and rejects ill-formed UTF-8 with a
|
||||
[`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with `allow_exceptions`
|
||||
set to `false`, a discarded value), rather than only failing later when the resulting value is dumped. Element
|
||||
(key) names and `binary` values (type `0x05`) are unaffected and are never validated, since they are read
|
||||
byte-by-byte as a C string, or are not required to hold text, respectively.
|
||||
(key) names and `binary` values (type `0x05`) are unaffected and are never validated on read, since they are read
|
||||
byte-by-byte as a C string, or are not required to hold text, respectively. `to_bson()` validates both string
|
||||
values and element names and throws
|
||||
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for ill-formed UTF-8 in either, so an
|
||||
object with such a key or value cannot be produced in the first place, even though `from_bson()` would accept it
|
||||
from another source.
|
||||
|
||||
??? example
|
||||
|
||||
|
||||
@@ -197,7 +197,9 @@ The library maps CBOR types to JSON value types as follows:
|
||||
[`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with
|
||||
`allow_exceptions` set to `false`, a discarded value), rather than only failing later when the resulting value is
|
||||
dumped. Byte strings (major type 2) are unaffected and are never validated, since they are not required to hold
|
||||
text.
|
||||
text. `to_cbor()` validates string values and object keys the same way and throws
|
||||
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for ill-formed UTF-8, so a value with
|
||||
such a string cannot be serialized in the first place.
|
||||
|
||||
!!! warning "Tagged items"
|
||||
|
||||
|
||||
@@ -153,14 +153,15 @@ The library maps MessagePack types to JSON value types as follows:
|
||||
This applies to the [SAX interface](../parsing/sax_interface.md) as well, as the key is read before it is passed
|
||||
on. Such input needs a general-purpose MessagePack library instead.
|
||||
|
||||
!!! warning "UTF-8 validation of string values"
|
||||
!!! warning "Ill-formed UTF-8 in string values"
|
||||
|
||||
The MessagePack specification requires `str` values (`fixstr`, `str 8`, `str 16`, `str 32`) to be valid UTF-8.
|
||||
This library validates the bytes of every such string (object keys included) at decode time and rejects
|
||||
ill-formed UTF-8 with a [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or,
|
||||
with `allow_exceptions` set to `false`, a discarded value), rather than only failing later when the resulting
|
||||
value is dumped. `bin`/`ext`/`fixext` values are unaffected and are never validated, since they are not required
|
||||
to hold text.
|
||||
The MessagePack specification explicitly allows a `str` value (`fixstr`, `str 8`, `str 16`, `str 32`) to contain
|
||||
a byte sequence that is not valid UTF-8, and expects a deserializer to hand the original bytes back unchanged.
|
||||
This library follows that: `from_msgpack()` reads `str` bytes (object keys included) as-is, without validating
|
||||
them, and `to_msgpack()` writes them back as-is, so such a value round-trips through `from_msgpack(to_msgpack(j))`
|
||||
byte for byte. However, [`dump()`](../../api/basic_json/dump.md) still requires valid UTF-8 and throws
|
||||
[`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for a value read this way, unless an
|
||||
error handler is passed that replaces or ignores the ill-formed bytes.
|
||||
|
||||
??? example
|
||||
|
||||
|
||||
@@ -47,6 +47,12 @@ The library uses the following mapping from JSON values types to UBJSON types ac
|
||||
|
||||
- strings with more than 9223372036854775807 bytes (theoretical)
|
||||
|
||||
!!! warning "UTF-8 validation of string values and object keys"
|
||||
|
||||
UBJSON's required string encoding is UTF-8. `to_ubjson()` validates the bytes of every string value and object
|
||||
key and throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316) for ill-formed UTF-8, so
|
||||
a value with such a string cannot be serialized in the first place.
|
||||
|
||||
!!! info "Unused UBJSON markers"
|
||||
|
||||
The following markers are not used in the conversion:
|
||||
@@ -120,6 +126,13 @@ The library maps UBJSON types to JSON value types as follows:
|
||||
|
||||
The mapping is **complete** in the sense that any UBJSON value can be converted to a JSON value.
|
||||
|
||||
!!! warning "UTF-8 validation of string values and object keys"
|
||||
|
||||
This library validates the bytes of every string value and object key at decode time and rejects ill-formed
|
||||
UTF-8 with a [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with
|
||||
`allow_exceptions` set to `false`, a discarded value), rather than only failing later when the resulting value
|
||||
is dumped.
|
||||
|
||||
??? example
|
||||
|
||||
```cpp
|
||||
|
||||
Reference in New Issue
Block a user