Skip to content

Commit babdd2c

Browse files
authored
Merge pull request #826 from jhawthorn/wbcheck_configure
Fix missing write barrier on Generator State
2 parents 8d08494 + c24342d commit babdd2c

1 file changed

Lines changed: 34 additions & 11 deletions

File tree

ext/json/ext/generator/generator.c

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,15 +1907,30 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
19071907
return Qnil;
19081908
}
19091909

1910+
struct configure_state_data {
1911+
JSON_Generator_State *state;
1912+
VALUE vstate; // Ruby object that owns the state, or Qfalse if stack-allocated
1913+
};
1914+
1915+
static inline void state_write_value(struct configure_state_data *data, VALUE *field, VALUE value)
1916+
{
1917+
if (RTEST(data->vstate)) {
1918+
RB_OBJ_WRITE(data->vstate, field, value);
1919+
} else {
1920+
*field = value;
1921+
}
1922+
}
1923+
19101924
static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
19111925
{
1912-
JSON_Generator_State *state = (JSON_Generator_State *)_arg;
1926+
struct configure_state_data *data = (struct configure_state_data *)_arg;
1927+
JSON_Generator_State *state = data->state;
19131928

1914-
if (key == sym_indent) { state->indent = string_config(val); }
1915-
else if (key == sym_space) { state->space = string_config(val); }
1916-
else if (key == sym_space_before) { state->space_before = string_config(val); }
1917-
else if (key == sym_object_nl) { state->object_nl = string_config(val); }
1918-
else if (key == sym_array_nl) { state->array_nl = string_config(val); }
1929+
if (key == sym_indent) { state_write_value(data, &state->indent, string_config(val)); }
1930+
else if (key == sym_space) { state_write_value(data, &state->space, string_config(val)); }
1931+
else if (key == sym_space_before) { state_write_value(data, &state->space_before, string_config(val)); }
1932+
else if (key == sym_object_nl) { state_write_value(data, &state->object_nl, string_config(val)); }
1933+
else if (key == sym_array_nl) { state_write_value(data, &state->array_nl, string_config(val)); }
19191934
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
19201935
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
19211936
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
@@ -1924,35 +1939,43 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
19241939
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
19251940
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
19261941
else if (key == sym_strict) { state->strict = RTEST(val); }
1927-
else if (key == sym_as_json) { state->as_json = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse; }
1942+
else if (key == sym_as_json) {
1943+
VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
1944+
state_write_value(data, &state->as_json, proc);
1945+
}
19281946
return ST_CONTINUE;
19291947
}
19301948

1931-
static void configure_state(JSON_Generator_State *state, VALUE config)
1949+
static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE config)
19321950
{
19331951
if (!RTEST(config)) return;
19341952

19351953
Check_Type(config, T_HASH);
19361954

19371955
if (!RHASH_SIZE(config)) return;
19381956

1957+
struct configure_state_data data = {
1958+
.state = state,
1959+
.vstate = vstate
1960+
};
1961+
19391962
// We assume in most cases few keys are set so it's faster to go over
19401963
// the provided keys than to check all possible keys.
1941-
rb_hash_foreach(config, configure_state_i, (VALUE)state);
1964+
rb_hash_foreach(config, configure_state_i, (VALUE)&data);
19421965
}
19431966

19441967
static VALUE cState_configure(VALUE self, VALUE opts)
19451968
{
19461969
GET_STATE(self);
1947-
configure_state(state, opts);
1970+
configure_state(state, self, opts);
19481971
return self;
19491972
}
19501973

19511974
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
19521975
{
19531976
JSON_Generator_State state = {0};
19541977
state_init(&state);
1955-
configure_state(&state, opts);
1978+
configure_state(&state, Qfalse, opts);
19561979

19571980
char stack_buffer[FBUFFER_STACK_SIZE];
19581981
FBuffer buffer = {

0 commit comments

Comments
 (0)