Skip to content

Commit c24342d

Browse files
committed
Fix missing write barrier on Generator State
Found by wbcheck WBCHECK ERROR: Missed write barrier detected! Parent object: 0x7b7b8487c450 (wb_protected: true) rb_obj_info_dump: 0x00007b7b8487c450 JSON/Generator/State/JSON::Ext::Generator::State JSON/Generator/State Reference counts - snapshot: 1, writebarrier: 0, current: 6, missed: 5 Missing reference to: 0x7b7b82f35a10 rb_obj_info_dump: 0x00007b7b82f35a10 T_STRING/String len: 1, capa: 15 "1" Missing reference to: 0x7b7b82f35e90 rb_obj_info_dump: 0x00007b7b82f35e90 T_STRING/String len: 1, capa: 15 "2" Missing reference to: 0x7b7b83629e50 rb_obj_info_dump: 0x00007b7b83629e50 T_STRING/String len: 1, capa: 15 "3" Missing reference to: 0x7b7b83b62190 rb_obj_info_dump: 0x00007b7b83b62190 T_STRING/String len: 1, capa: 15 "4" Missing reference to: 0x7b7b83629490 rb_obj_info_dump: 0x00007b7b83629490 T_STRING/String len: 1, capa: 15 "5"
1 parent c079793 commit c24342d

File tree

1 file changed

+34
-11
lines changed

1 file changed

+34
-11
lines changed

ext/json/ext/generator/generator.c

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,15 +1609,30 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
16091609
return Qnil;
16101610
}
16111611

1612+
struct configure_state_data {
1613+
JSON_Generator_State *state;
1614+
VALUE vstate; // Ruby object that owns the state, or Qfalse if stack-allocated
1615+
};
1616+
1617+
static inline void state_write_value(struct configure_state_data *data, VALUE *field, VALUE value)
1618+
{
1619+
if (RTEST(data->vstate)) {
1620+
RB_OBJ_WRITE(data->vstate, field, value);
1621+
} else {
1622+
*field = value;
1623+
}
1624+
}
1625+
16121626
static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
16131627
{
1614-
JSON_Generator_State *state = (JSON_Generator_State *)_arg;
1628+
struct configure_state_data *data = (struct configure_state_data *)_arg;
1629+
JSON_Generator_State *state = data->state;
16151630

1616-
if (key == sym_indent) { state->indent = string_config(val); }
1617-
else if (key == sym_space) { state->space = string_config(val); }
1618-
else if (key == sym_space_before) { state->space_before = string_config(val); }
1619-
else if (key == sym_object_nl) { state->object_nl = string_config(val); }
1620-
else if (key == sym_array_nl) { state->array_nl = string_config(val); }
1631+
if (key == sym_indent) { state_write_value(data, &state->indent, string_config(val)); }
1632+
else if (key == sym_space) { state_write_value(data, &state->space, string_config(val)); }
1633+
else if (key == sym_space_before) { state_write_value(data, &state->space_before, string_config(val)); }
1634+
else if (key == sym_object_nl) { state_write_value(data, &state->object_nl, string_config(val)); }
1635+
else if (key == sym_array_nl) { state_write_value(data, &state->array_nl, string_config(val)); }
16211636
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
16221637
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
16231638
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
@@ -1626,35 +1641,43 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
16261641
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
16271642
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
16281643
else if (key == sym_strict) { state->strict = RTEST(val); }
1629-
else if (key == sym_as_json) { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; }
1644+
else if (key == sym_as_json) {
1645+
VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
1646+
state_write_value(data, &state->as_json, proc);
1647+
}
16301648
return ST_CONTINUE;
16311649
}
16321650

1633-
static void configure_state(JSON_Generator_State *state, VALUE config)
1651+
static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE config)
16341652
{
16351653
if (!RTEST(config)) return;
16361654

16371655
Check_Type(config, T_HASH);
16381656

16391657
if (!RHASH_SIZE(config)) return;
16401658

1659+
struct configure_state_data data = {
1660+
.state = state,
1661+
.vstate = vstate
1662+
};
1663+
16411664
// We assume in most cases few keys are set so it's faster to go over
16421665
// the provided keys than to check all possible keys.
1643-
rb_hash_foreach(config, configure_state_i, (VALUE)state);
1666+
rb_hash_foreach(config, configure_state_i, (VALUE)&data);
16441667
}
16451668

16461669
static VALUE cState_configure(VALUE self, VALUE opts)
16471670
{
16481671
GET_STATE(self);
1649-
configure_state(state, opts);
1672+
configure_state(state, self, opts);
16501673
return self;
16511674
}
16521675

16531676
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
16541677
{
16551678
JSON_Generator_State state = {0};
16561679
state_init(&state);
1657-
configure_state(&state, opts);
1680+
configure_state(&state, Qfalse, opts);
16581681

16591682
char stack_buffer[FBUFFER_STACK_SIZE];
16601683
FBuffer buffer = {

0 commit comments

Comments
 (0)