Skip to content

Commit ab6972d

Browse files
committed
Add missing write barrier in ParserConfig
This couldn't possibly lead to a crash unless you'd mess with GC.stress or `send(:initialize)` on an old object. But for correctness, it should be there.
1 parent 4a1a4a4 commit ab6972d

1 file changed

Lines changed: 28 additions & 12 deletions

File tree

ext/json/ext/parser/parser.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,9 +1471,22 @@ static VALUE convert_encoding(VALUE source)
14711471
return rb_funcall(source, i_encode, 1, Encoding_UTF_8);
14721472
}
14731473

1474+
struct parser_config_init_args {
1475+
JSON_ParserConfig *config;
1476+
VALUE self;
1477+
};
1478+
1479+
static void parser_config_wb_write(VALUE self, VALUE *dest, VALUE val)
1480+
{
1481+
*dest = val;
1482+
if (self) RB_OBJ_WRITTEN(self, Qundef, val);
1483+
}
1484+
14741485
static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
14751486
{
1476-
JSON_ParserConfig *config = (JSON_ParserConfig *)data;
1487+
struct parser_config_init_args *args = (struct parser_config_init_args *)data;
1488+
JSON_ParserConfig *config = args->config;
1489+
VALUE self = args->self;
14771490

14781491
if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
14791492
else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
@@ -1482,15 +1495,15 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
14821495
else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
14831496
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
14841497
else if (key == sym_freeze) { config->freeze = RTEST(val); }
1485-
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
1498+
else if (key == sym_on_load) { parser_config_wb_write(self, &config->on_load_proc, RTEST(val) ? val : Qfalse); }
14861499
else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
14871500
else if (key == sym_decimal_class) {
14881501
if (RTEST(val)) {
14891502
if (rb_respond_to(val, i_try_convert)) {
1490-
config->decimal_class = val;
1503+
parser_config_wb_write(self, &config->decimal_class, val);
14911504
config->decimal_method_id = i_try_convert;
14921505
} else if (rb_respond_to(val, i_new)) {
1493-
config->decimal_class = val;
1506+
parser_config_wb_write(self, &config->decimal_class, val);
14941507
config->decimal_method_id = i_new;
14951508
} else if (RB_TYPE_P(val, T_CLASS)) {
14961509
VALUE name = rb_class_name(val);
@@ -1499,15 +1512,15 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
14991512
if (last_colon) {
15001513
const char *mod_path_end = last_colon - 1;
15011514
VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
1502-
config->decimal_class = rb_path_to_class(mod_path);
1515+
parser_config_wb_write(self, &config->decimal_class, rb_path_to_class(mod_path));
15031516

15041517
const char *method_name_beg = last_colon + 1;
15051518
long before_len = method_name_beg - name_cstr;
15061519
long len = RSTRING_LEN(name) - before_len;
15071520
VALUE method_name = rb_str_substr(name, before_len, len);
15081521
config->decimal_method_id = SYM2ID(rb_str_intern(method_name));
15091522
} else {
1510-
config->decimal_class = rb_mKernel;
1523+
parser_config_wb_write(self, &config->decimal_class, rb_mKernel);
15111524
config->decimal_method_id = SYM2ID(rb_str_intern(name));
15121525
}
15131526
}
@@ -1517,16 +1530,21 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
15171530
return ST_CONTINUE;
15181531
}
15191532

1520-
static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
1533+
static void parser_config_init(JSON_ParserConfig *config, VALUE opts, VALUE self)
15211534
{
15221535
config->max_nesting = 100;
15231536

1537+
struct parser_config_init_args args = {
1538+
.config = config,
1539+
.self = self,
1540+
};
1541+
15241542
if (!NIL_P(opts)) {
15251543
Check_Type(opts, T_HASH);
15261544
if (RHASH_SIZE(opts) > 0) {
15271545
// We assume in most cases few keys are set so it's faster to go over
15281546
// the provided keys than to check all possible keys.
1529-
rb_hash_foreach(opts, parser_config_init_i, (VALUE)config);
1547+
rb_hash_foreach(opts, parser_config_init_i, (VALUE)&args);
15301548
}
15311549

15321550
}
@@ -1560,9 +1578,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
15601578
rb_check_frozen(self);
15611579
GET_PARSER_CONFIG;
15621580

1563-
parser_config_init(config, opts);
1564-
1565-
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
1581+
parser_config_init(config, opts, self);
15661582

15671583
return self;
15681584
}
@@ -1624,7 +1640,7 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
16241640

16251641
JSON_ParserConfig _config = {0};
16261642
JSON_ParserConfig *config = &_config;
1627-
parser_config_init(config, opts);
1643+
parser_config_init(config, opts, false);
16281644

16291645
return cParser_parse(config, Vsource);
16301646
}

0 commit comments

Comments
 (0)