From cdcc3a50fe825516e7c6f08e073d030a61f37fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Barri=C3=A9?= Date: Thu, 27 Nov 2025 16:12:17 +0100 Subject: [PATCH 1/2] Test and restore behavior around to_json changing depth When serializing an Array, and one of the elements of the Array requires calling `to_json`, if the depth is changed, it will be used for the next entries, which wasn't the case before 5abd43490714460e1ec1fa382f82a09485eed563, and is not the case with TruffleRuby and JRuby. Additionally, with TruffleRuby and JRuby the state's depth after the `to_json` call is used to close the Array, which isn't the case with CRuby. --- ext/json/ext/generator/generator.c | 2 ++ test/json/json_generator_test.rb | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index 6ece9f05..58d22ea7 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -1295,6 +1295,8 @@ static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *d VALUE tmp; if (rb_respond_to(obj, i_to_json)) { tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data)); + GET_STATE(data->vstate); + data->depth = state->depth; Check_Type(tmp, T_STRING); fbuffer_append_str(buffer, tmp); } else { diff --git a/test/json/json_generator_test.rb b/test/json/json_generator_test.rb index c01ed678..fa102f06 100755 --- a/test/json/json_generator_test.rb +++ b/test/json/json_generator_test.rb @@ -321,6 +321,30 @@ def test_allow_nan end end + def test_depth_bad_to_json + obj = Object.new + def obj.to_json(state) + state.depth += 1 + "{#{state.object_nl}"\ + "#{state.indent * state.depth}\"foo\":#{state.space}1#{state.object_nl}"\ + "#{state.indent * (state.depth - 1)}}" + end + indent = " " * 2 if RUBY_ENGINE != "ruby" + assert_equal <<~JSON.chomp, JSON.pretty_generate([obj] * 2) + [ + { + "foo": 1 + }, + { + "foo": 1 + } + #{indent}] + JSON + state = JSON::State.new(object_nl: "\n", array_nl: "\n", space: " ", indent: " ") + state.generate(obj) + assert_equal 1, state.depth + end + def test_depth pretty = { object_nl: "\n", array_nl: "\n", space: " ", indent: " " } state = JSON.state.new(**pretty) From 6195c2ab03bb98b27d1a255b0a8b9a94251d19e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Barri=C3=A9?= Date: Fri, 28 Nov 2025 15:53:58 +0100 Subject: [PATCH 2/2] Reproduce C ext behavior of ignoring mutated depth in arrays --- java/src/json/ext/Generator.java | 4 ++-- java/src/json/ext/GeneratorState.java | 2 +- lib/json/truffle_ruby/generator.rb | 2 +- test/json/json_generator_test.rb | 8 +++++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/java/src/json/ext/Generator.java b/java/src/json/ext/Generator.java index 78281dbd..0caa6948 100644 --- a/java/src/json/ext/Generator.java +++ b/java/src/json/ext/Generator.java @@ -462,10 +462,10 @@ static void generateArray(ThreadContext context, Session session, RubyArray