From f16961ec795776b283e51d6d768d579520f24196 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 6 Mar 2026 13:32:33 +0900 Subject: [PATCH 1/6] [ruby/rubygems] Remove dead code in dependency installer tests Remove unused si.to_yaml calls that stored YAML at URLs that were never fetched. With the pure-Ruby parser, NilClass no longer has to_yaml, but these lines were dead code regardless. https://github.com/ruby/rubygems/commit/6ab25e49ac --- test/rubygems/test_gem_dependency_installer.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/rubygems/test_gem_dependency_installer.rb b/test/rubygems/test_gem_dependency_installer.rb index 3e10c0883aaebc..8d9caf7d90b9a4 100644 --- a/test/rubygems/test_gem_dependency_installer.rb +++ b/test/rubygems/test_gem_dependency_installer.rb @@ -677,8 +677,7 @@ def test_install_force util_setup_gems FileUtils.mv @b1_gem, @tempdir - si = util_setup_spec_fetcher @b1 - @fetcher.data["http://gems.example.com/gems/yaml"] = si.to_yaml + util_setup_spec_fetcher @b1 inst = nil Dir.chdir @tempdir do @@ -955,9 +954,7 @@ def test_install_remote_platform_newer s.platform = Gem::Platform.new %w[cpu other_platform 1] end - si = util_setup_spec_fetcher @a1, a2_o - - @fetcher.data["http://gems.example.com/gems/yaml"] = si.to_yaml + util_setup_spec_fetcher @a1, a2_o a1_data = nil a2_o_data = nil From f56310de4a2d557dca7693954949f19d15906965 Mon Sep 17 00:00:00 2001 From: thesmartshadow Date: Thu, 5 Mar 2026 18:58:27 +0000 Subject: [PATCH 2/6] [ruby/json] Reject negative depth; add overflow guards to prevent hang/crash https://github.com/ruby/json/commit/de993aa766 --- ext/json/generator/generator.c | 15 +++++++++++++-- test/json/json_generator_test.rb | 10 ++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index e699d31812c45e..a6302691d9fd6b 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -1575,6 +1575,17 @@ static long long_config(VALUE num) return RTEST(num) ? FIX2LONG(num) : 0; } +// depth must never be negative; reject early with a clear error. +static long depth_config(VALUE num) +{ + if (!RTEST(num)) return 0; + long d = NUM2LONG(num); + if (RB_UNLIKELY(d < 0)) { + rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d); + } + return d; +} + /* * call-seq: max_nesting=(depth) * @@ -1731,7 +1742,7 @@ static VALUE cState_depth_set(VALUE self, VALUE depth) { rb_check_frozen(self); GET_STATE(self); - state->depth = long_config(depth); + state->depth = depth_config(depth); return Qnil; } @@ -1796,7 +1807,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg) else if (key == sym_max_nesting) { state->max_nesting = long_config(val); } else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); } else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); } - else if (key == sym_depth) { state->depth = long_config(val); } + else if (key == sym_depth) { state->depth = depth_config(val); } else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); } else if (key == sym_script_safe) { state->script_safe = RTEST(val); } else if (key == sym_escape_slash) { state->script_safe = RTEST(val); } diff --git a/test/json/json_generator_test.rb b/test/json/json_generator_test.rb index 9a8ee5157ed6bc..eb5a8ca59e0ee6 100755 --- a/test/json/json_generator_test.rb +++ b/test/json/json_generator_test.rb @@ -1045,4 +1045,14 @@ def test_nesting_recovery assert_equal 0, state.depth assert_equal '{"a":1}', state.generate({ a: 1 }) end + + def test_negative_depth_raises + assert_raise(ArgumentError) do + JSON.generate({"a" => 1}, depth: -1) + end + assert_raise(ArgumentError) do + JSON.state.new(depth: -1) + end + end + end From cd80e2382375ddb34c69079fa1e7f09821c4f528 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 6 Mar 2026 08:51:43 +0100 Subject: [PATCH 3/6] [ruby/json] fbuffer.h: Use size_t over unsigned long unsigned long is only 32b on some platforms. https://github.com/ruby/json/commit/0a4fb79cd9 --- ext/json/fbuffer/fbuffer.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h index 8ce029a8c49dfd..d5fd5ea26adccc 100644 --- a/ext/json/fbuffer/fbuffer.h +++ b/ext/json/fbuffer/fbuffer.h @@ -11,11 +11,11 @@ enum fbuffer_type { typedef struct FBufferStruct { enum fbuffer_type type; - unsigned long initial_length; - unsigned long len; - unsigned long capa; + size_t initial_length; + size_t len; + size_t capa; #if JSON_DEBUG - unsigned long requested; + size_t requested; #endif char *ptr; VALUE io; @@ -32,12 +32,12 @@ typedef struct FBufferStruct { static void fbuffer_free(FBuffer *fb); static void fbuffer_clear(FBuffer *fb); -static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len); +static void fbuffer_append(FBuffer *fb, const char *newstr, size_t len); static void fbuffer_append_long(FBuffer *fb, long number); static inline void fbuffer_append_char(FBuffer *fb, char newchr); static VALUE fbuffer_finalize(FBuffer *fb); -static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size) +static void fbuffer_stack_init(FBuffer *fb, size_t initial_length, char *stack_buffer, size_t stack_buffer_size) { fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT; if (stack_buffer) { @@ -50,7 +50,7 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char * #endif } -static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed) +static inline void fbuffer_consumed(FBuffer *fb, size_t consumed) { #if JSON_DEBUG if (consumed > fb->requested) { @@ -79,7 +79,7 @@ static void fbuffer_flush(FBuffer *fb) fbuffer_clear(fb); } -static void fbuffer_realloc(FBuffer *fb, unsigned long required) +static void fbuffer_realloc(FBuffer *fb, size_t required) { if (required > fb->capa) { if (fb->type == FBUFFER_STACK_ALLOCATED) { @@ -94,7 +94,7 @@ static void fbuffer_realloc(FBuffer *fb, unsigned long required) } } -static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested) +static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested) { if (RB_UNLIKELY(fb->io)) { if (fb->capa < FBUFFER_IO_BUFFER_SIZE) { @@ -108,7 +108,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested) } } - unsigned long required; + size_t required; if (RB_UNLIKELY(!fb->ptr)) { fb->ptr = ALLOC_N(char, fb->initial_length); @@ -120,7 +120,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested) fbuffer_realloc(fb, required); } -static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested) +static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested) { #if JSON_DEBUG fb->requested = requested; @@ -131,13 +131,13 @@ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested) } } -static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, unsigned long len) +static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, size_t len) { MEMCPY(fb->ptr + fb->len, newstr, char, len); fbuffer_consumed(fb, len); } -static inline void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len) +static inline void fbuffer_append(FBuffer *fb, const char *newstr, size_t len) { if (len > 0) { fbuffer_inc_capa(fb, len); @@ -162,7 +162,7 @@ static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr) static void fbuffer_append_str(FBuffer *fb, VALUE str) { const char *ptr; - unsigned long len; + size_t len; RSTRING_GETMEM(str, ptr, len); fbuffer_append(fb, ptr, len); @@ -171,7 +171,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str) static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat) { const char *ptr; - unsigned long len; + size_t len; RSTRING_GETMEM(str, ptr, len); fbuffer_inc_capa(fb, repeat * len); From 9356837d1a436a75ba3b35234d7678eeee158ec5 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 6 Mar 2026 09:03:58 +0100 Subject: [PATCH 4/6] [ruby/json] Release 2.19.0 https://github.com/ruby/json/commit/a11acc1ff4 --- ext/json/lib/json/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb index 95b88571005b7e..3f73c0d97dcc6c 100644 --- a/ext/json/lib/json/version.rb +++ b/ext/json/lib/json/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JSON - VERSION = '2.18.1' + VERSION = '2.19.0' end From 66c3ff3f18f7fd6b46b14762352085650a13800b Mon Sep 17 00:00:00 2001 From: git Date: Fri, 6 Mar 2026 08:06:44 +0000 Subject: [PATCH 5/6] Update default gems list at 9356837d1a436a75ba3b35234d7678 [ci skip] --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 7a73e16f9f54cb..79b5cc9ff87330 100644 --- a/NEWS.md +++ b/NEWS.md @@ -64,7 +64,7 @@ releases. * RubyGems 4.1.0.dev * bundler 4.1.0.dev -* json 2.18.1 +* json 2.19.0 * 2.18.0 to [v2.18.1][json-v2.18.1] * openssl 4.0.1 * 4.0.0 to [v4.0.1][openssl-v4.0.1] From d5d144c149d3beabbfb262e3994f60552469181b Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 2 Mar 2026 02:29:09 +0900 Subject: [PATCH 6/6] parse.y: Split forwarding argument in method and lambda Eliminate the lambda argument conditions from the action. --- parse.y | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/parse.y b/parse.y index 6813b396332b00..b91b141cc65375 100644 --- a/parse.y +++ b/parse.y @@ -2773,7 +2773,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary) %type if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure %type args arg_splat call_args opt_call_args %type paren_args opt_paren_args -%type args_tail block_args_tail f_args-opt_tail block_args-opt_tail +%type args_tail block_args_tail block_args-opt_tail %type command_args aref_args %type opt_block_arg block_arg %type var_ref var_lhs @@ -2788,7 +2788,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary) %type do bv_decls opt_bv_decl bvar %type lambda brace_body do_body %type lambda_body -%type f_larglist +%type f_larglist f_largs largs_tail %type brace_block cmd_brace_block do_block lhs none fitem %type mlhs_head mlhs_item mlhs_node %type mlhs mlhs_basic mlhs_inner @@ -5103,19 +5103,19 @@ lambda : tLAMBDA[lpar] } ; -f_larglist : '(' f_args opt_bv_decl ')' +f_larglist : '(' f_largs[args] opt_bv_decl ')' { p->ctxt.in_argdef = 0; - $$ = $f_args; + $$ = $args; p->max_numparam = ORDINAL_PARAM; - /*% ripper: paren!($:f_args) %*/ + /*% ripper: paren!($:args) %*/ } - | f_args + | f_largs[args] { p->ctxt.in_argdef = 0; - if (!args_info_empty_p(&$f_args->nd_ainfo)) + if (!args_info_empty_p(&$args->nd_ainfo)) p->max_numparam = ORDINAL_PARAM; - $$ = $f_args; + $$ = $args; } ; @@ -6243,16 +6243,18 @@ f_arglist : f_paren_args args_tail : args_tail_basic(arg_value) | args_forward { - ID fwd = $args_forward; - if (lambda_beginning_p() || - (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest)) { - yyerror0("unexpected ... in lambda argument"); - fwd = 0; - } - else { - add_forwarding_args(p); - } - $$ = new_args_tail(p, 0, fwd, arg_FWD_BLOCK, &@args_forward); + add_forwarding_args(p); + $$ = new_args_tail(p, 0, $args_forward, arg_FWD_BLOCK, &@args_forward); + $$->nd_ainfo.forwarding = 1; + /*% ripper: [Qnil, $:args_forward, Qnil] %*/ + } + ; + +largs_tail : args_tail_basic(arg_value) + | args_forward + { + yyerror1(&@args_forward, "unexpected ... in lambda argument"); + $$ = new_args_tail(p, 0, 0, 0, &@args_forward); $$->nd_ainfo.forwarding = 1; /*% ripper: [Qnil, $:args_forward, Qnil] %*/ } @@ -6329,19 +6331,27 @@ args_tail : args_tail_basic(arg_value) } ; -f_args-opt_tail : opt_args_tail(args_tail) +%rule f_args-opt_tail(tail) + : opt_args_tail(tail) ; -f_args : args-list(arg_value, f_args-opt_tail) - | f_arg[pre] f_args-opt_tail[tail] + +%rule f_args-list(tail) + : args-list(arg_value, f_args-opt_tail(tail)) + | f_arg[pre] opt_args_tail(tail)[tail] { $$ = new_args(p, $pre, 0, 0, 0, $tail, &@$); /*% ripper: params!($:pre, Qnil, Qnil, Qnil, *$:tail[0..2]) %*/ } - | tail-only-args(args_tail) + | tail-only-args(tail) | f_empty_arg ; +f_args : f_args-list(args_tail) + ; + +f_largs : f_args-list(largs_tail) + ; args_forward : tBDOT3 {