`spe` is the string end, so if the escape is incomplete, it doesn't
mean we reached the end of stream, hence it's a syntax error, not
an EOS error.
https://github.com/ruby/json/commit/c1a4372837
Convert non-Proc on_load callbacks through to_proc and validate the result in the shared parser configuration. Previously, arbitrary values were stored and passed directly to rb_proc_call_with_block.
Cover Method callbacks in JSON.parse, JSON::Coder, and ResumableParser, along with invalid types, invalid conversion results, and nil or false callbacks.
https://github.com/ruby/json/commit/672da19fd5
GzipReader offers both a read and to_io method. The read method returns
the uncompressed file as a string. The to_io method returns the
compressed file. The JSON.load method first tests for the to_io method
and uses it before testing for the read method. This results in reading
the compressed file, which is invalid JSON.
Instead, we now test for the read method first.
https://github.com/ruby/json/commit/b6a5d35245
Convert non-Proc callbacks through to_proc and validate the result in both configuration and the as_json setter. rb_convert_type accepts unrelated T_DATA objects without conversion, allowing them to reach Proc APIs and crash.
Cover Method callbacks, invalid callback types, and to_proc returning a non-Proc object.
https://github.com/ruby/json/commit/f5c889de9c
With allow_invalid_escape, the JRuby decoder appended the code point read
after a stray backslash with append(int), which writes only its low byte.
"\\é" became "\xE9" and "\\あ" became "B", where the C extension
keeps the character. Use writeUtf8Char, as the other code point paths do.
https://github.com/ruby/json/commit/edb3b20d6d
JSON::State.default_sort_keys_proc is registered at extension load time
so it's owned by the main Ractor.
When we implement the registration table on each Ractor storing another
Ractor's unshareable Proc into that slot leaves a dangling reference
when the owning Ractor runs a local GC.
This commit ensures that we won't use a shareable proc by raising a
Ractor::IsolationError.
The C extension walks the given hash and writes only the keys present
(generator.c:1860), and since #1076 the pure generator does the same.
The Java one re-wrote every option with its class default, so any
configure or merge silently reset max_nesting, allow_nan, ascii_only,
script_safe, strict, buffer_initial_length, allow_duplicate_key,
as_json and sort_keys.
Re-enables the two tests #1076 marked pending on JRuby.
https://github.com/ruby/json/commit/bbc73fb69d
The pure-Ruby generator's private _configure gives every keyword a literal
default, so a call that passes one option silently resets the other fifteen.
The method is also aliased as merge, so a state built with indent/object_nl
starts emitting compact JSON after any later configure call.
The C extension does not behave this way. configure_state_i walks only the
keys actually present in the hash, so State#merge really merges there.
Default the keywords to the current ivars so the pure generator agrees.
initialize already assigns every ivar to its literal default before calling
_configure(**opts), so construction is unchanged.
https://github.com/ruby/json/commit/46fbe24b04
Since https://github.com/ruby/json/commit/ebf0f29, `load_file` and `load_file!` forward their arguments to
`parse` and `parse!` with `...` after a leading parameter. Ruby 2.7 accepts `...` only on its own;
a leading parameter before it was added in Ruby 3.0 and reached the 2.7 series in 2.7.3, so on Ruby 2.7.0
through 2.7.2 requiring json 3.0 raises a `SyntaxError` at `lib/json/common.rb`, while the gemspec still allows
Ruby 2.7 as a whole.
`parse` and `parse!` take keyword arguments only, so forwarding `**options` passes exactly what `...` passed,
on every Ruby the gem supports.
A `method_missing` helper in the parser tests used the same form; it takes an anonymous splat now,
so the test suite itself loads on those versions.
Checked with `ruby -c` on Ruby 2.7.0, 2.7.2, 2.7.3, and 3.0.7, and with the test suite on Ruby 2.7.2 and 3.0.7.
https://github.com/ruby/json/commit/29dad14674
I really wanted to get rid of this because the argument parsing is
awful and costly.
But `rdoc` has been using this positional argument for decades,
and while the fix has been merged, having to upgrade to the latest
rdoc is a bit too disruptive.
https://github.com/ruby/json/commit/566bd7c108
The C parser guards leading-first surrogate pairs but silently accepts
a lone trailing surrogate, encoding U+DC00..U+DFFF as three UTF-8 bytes
into the output buffer. The returned Ruby String is tagged UTF-8 but
fails valid_encoding? and raises misleading errors from downstream
String operations (upcase, split, regex, encode, JSON.generate).
Add a symmetric branch alongside the leading-surrogate check to raise
JSON::ParserError at the parse boundary. Extend test_invalid_surogates
with the new cases and move the three JSONTestSuite fixtures that this
fix newly rejects from INVALID_ENCODING_TESTS into UNDEFINED_FAILING,
closing the CRuby/JRuby parser parity gap documented in the file.
https://github.com/ruby/json/commit/82bf6bedcf
In strict mode, a Symbol whose name is not UTF-8 compatible was passed to
generate_json_string, which handed the as_json result to
raw_generate_json_string without checking its type. A non-String result was
then read as a String, segfaulting the process.
Route strict symbols through the T_STRING case of generate_json_general so
they reuse its as_json handling. That re-dispatches the result by type, and
its as_json_called flag stops a symbol returned by as_json from recursing.
https://github.com/ruby/json/commit/2d73e6bdfe
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>