Skip to content

Commit 79b6e16

Browse files
committed
Ensure Generator::State is kept on the stack
Fix: #929 When calling `cState_partial_generate` from `mHash_to_json` or other `to_json` funcs, `VState` becomes unreachable very quickly, hence the compiler may optimize it out of the stack, and make it invisible to the GC stack scanning. This is particularly liekly given how aggressively we inline. Repro: ```ruby require 'json' test_data = { "flag" => true, "data" => 10000.times.map { [1.0] }, :flag => false, } 10.times do test_data.to_json end ``` But in practice the cause was just that the issued warning calls Hash#inspect on a big hash, which triggers GC. So it can be triggered even more reliably with: ```ruby require 'json' module JSON module Common def self.on_mixed_keys_hash(...) GC.start end end end test_data = { "flag" => true, "data" => 10000.times.map { [1.0] }, :flag => false, } test_data.to_json ```
1 parent 062fcdd commit 79b6e16

File tree

2 files changed

+6
-1
lines changed

2 files changed

+6
-1
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
### Unreleased
44

5+
* Fix a potential crash in very specific circumstance if GC triggers during a call to `to_json`
6+
without first invoking a user defined `#to_json` method.
7+
58
### 2025-12-11 (2.18.0)
69

710
* Add `:allow_control_characters` parser options, to allow JSON strings containing unescaped ASCII control characters (e.g. newlines).

ext/json/ext/generator/generator.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1540,7 +1540,9 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
15401540
.obj = obj,
15411541
.func = func
15421542
};
1543-
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
1543+
VALUE result = rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
1544+
RB_GC_GUARD(self);
1545+
return result;
15441546
}
15451547

15461548
/* call-seq:

0 commit comments

Comments
 (0)