From 2ecb368eb3bbaab8977e0d72777f2a7782957b0b Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sat, 26 Sep 2026 09:25:37 +0200 Subject: [PATCH] Ensure `default_sort_keys_proc` isn't reassigned. It's assignable from Ruby simply for the gem's own initialization, but it should never be re-assigned later. Fix: https://github.com/ruby/json/pull/1079 --- ext/json/ext/generator/generator.c | 3 +++ lib/json/common.rb | 8 -------- lib/json/ext.rb | 15 ++++++++++++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index d0d048751..0b7397c56 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -1733,6 +1733,9 @@ static VALUE cState_set_default_sort_keys_proc(VALUE self, VALUE proc) if (!rb_obj_is_proc(proc)) { rb_raise(rb_eTypeError, "sort_key_proc must be a Proc"); } + if (default_sort_keys_proc) { + rb_raise(rb_eArgError, "sort_key_proc can only be set once"); + } return default_sort_keys_proc = proc; } diff --git a/lib/json/common.rb b/lib/json/common.rb index 82d334061..3b5e3157a 100644 --- a/lib/json/common.rb +++ b/lib/json/common.rb @@ -80,14 +80,6 @@ def parser=(parser) # :nodoc: def generator=(generator) # :nodoc: old, $VERBOSE = $VERBOSE, nil - # The default proc used when the +sort_keys+ generation option is +true+. - # It returns a new hash with the entries sorted by their keys. - sort_keys_proc = ->(hash) { hash.sort.to_h } - if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda) - sort_keys_proc = Ractor.shareable_lambda(&sort_keys_proc) - end - generator::State.default_sort_keys_proc = sort_keys_proc - @generator = generator if generator.const_defined?(:GeneratorMethods) generator_methods = generator::GeneratorMethods diff --git a/lib/json/ext.rb b/lib/json/ext.rb index da17df1e8..8c8c6f258 100644 --- a/lib/json/ext.rb +++ b/lib/json/ext.rb @@ -32,13 +32,22 @@ def parse Ext::Parser::Config = Ext::ParserConfig JSON.parser = Ext::Parser - if RUBY_ENGINE == 'truffleruby' + generator = if RUBY_ENGINE == 'truffleruby' require 'json/truffle_ruby/generator' - JSON.generator = JSON::TruffleRuby::Generator + JSON::TruffleRuby::Generator else require 'json/ext/generator' - JSON.generator = Generator + Generator end + + # The default proc used when the +sort_keys+ generation option is +true+. + # It returns a new hash with the entries sorted by their keys. + sort_keys_proc = ->(hash) { hash.sort.to_h } + if defined?(::Ractor) && Ractor.respond_to?(:shareable_lambda) + sort_keys_proc = Ractor.shareable_lambda(&sort_keys_proc) + end + generator::State.default_sort_keys_proc = sort_keys_proc + JSON.generator = generator end if defined?(ResumableParser) # Not yet available on JRuby