Skip to content

Commit 37f8a2e

Browse files
committed
Ensure Generator::State is kept on the stack
Fix: #929 I don't know how it's possible, but somehow the `self` reference is optimized out of the stack. Perhaps because we inline so aggressively that the compiler end up spilling it on the heap. 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 37f8a2e

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)