json 2.19.4 → 2.19.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +10 -1
- data/ext/json/ext/fbuffer/fbuffer.h +10 -1
- data/ext/json/ext/generator/generator.c +21 -7
- data/ext/json/ext/parser/parser.c +35 -13
- data/lib/json/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d2f786d8fccfe7906f9ec68f2a8f1cb9b4fb458029b46e3bba7904a6e22e443f
|
|
4
|
+
data.tar.gz: 3fe8d97828cc573a98f4a0ccd88c2dc1fb008437dc115a1cd4d631b7a16f9df1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a39aec470a7ec7da944a8361ea219352f1216b3a4c4b2de7dd35fc87d4c791286f63b7744349ca4da607c37e53b1fecf450e62ef6cd02d0147eba0fb1edf5c2
|
|
7
|
+
data.tar.gz: 8cd952ae28ad7bc52f92ce49cd5cc6411835e3801a2c5cfc4a4b6d503a4bdb3dea3d726a4c4b2f7a75f0d3ec68f2d948bec52588cda37669c7d80ced0d527bb8
|
data/CHANGES.md
CHANGED
|
@@ -2,9 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
### Unreleased
|
|
4
4
|
|
|
5
|
+
### 2026-05-28 (2.19.6)
|
|
6
|
+
|
|
7
|
+
* Cleanly handle overly large `depth` generator argument.
|
|
8
|
+
* Add missing write barrier in `ParserConfig`.
|
|
9
|
+
|
|
10
|
+
### 2026-05-04 (2.19.5)
|
|
11
|
+
|
|
12
|
+
* Cap the parser to emit a maximum of 5 deprecation warnings per document. Emitting more is not helpful.
|
|
13
|
+
|
|
5
14
|
### 2026-04-19 (2.19.4)
|
|
6
15
|
|
|
7
|
-
* Fix parsing of out of range floats (very large exponents that lead
|
|
16
|
+
* Fix parsing of out of range floats (very large exponents that lead to either `0.0` or `Inf`).
|
|
8
17
|
|
|
9
18
|
### 2026-03-25 (2.19.3)
|
|
10
19
|
|
|
@@ -131,6 +131,15 @@ static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
static inline size_t fbuffer_size_mul_or_raise(size_t a, size_t b)
|
|
135
|
+
{
|
|
136
|
+
size_t result = a * b;
|
|
137
|
+
if (RB_UNLIKELY(a != 0 && (result / a) != b)) {
|
|
138
|
+
rb_raise(rb_eArgError, "Buffer overflow, the resulting document is too large to be generated");
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, size_t len)
|
|
135
144
|
{
|
|
136
145
|
MEMCPY(fb->ptr + fb->len, newstr, char, len);
|
|
@@ -175,7 +184,7 @@ static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
|
|
|
175
184
|
size_t len;
|
|
176
185
|
RSTRING_GETMEM(str, ptr, len);
|
|
177
186
|
|
|
178
|
-
fbuffer_inc_capa(fb, repeat
|
|
187
|
+
fbuffer_inc_capa(fb, fbuffer_size_mul_or_raise(repeat, len));
|
|
179
188
|
while (repeat) {
|
|
180
189
|
#if JSON_DEBUG
|
|
181
190
|
fb->requested = len;
|
|
@@ -819,9 +819,17 @@ static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
|
|
|
819
819
|
return Qundef;
|
|
820
820
|
}
|
|
821
821
|
|
|
822
|
+
static inline int json_str_coderange(VALUE str) {
|
|
823
|
+
int coderange = RB_ENC_CODERANGE(str);
|
|
824
|
+
if (coderange == RUBY_ENC_CODERANGE_UNKNOWN) {
|
|
825
|
+
coderange = rb_enc_str_coderange(str);
|
|
826
|
+
}
|
|
827
|
+
return coderange;
|
|
828
|
+
}
|
|
829
|
+
|
|
822
830
|
static inline bool valid_json_string_p(VALUE str)
|
|
823
831
|
{
|
|
824
|
-
int coderange =
|
|
832
|
+
int coderange = json_str_coderange(str);
|
|
825
833
|
|
|
826
834
|
if (RB_LIKELY(coderange == ENC_CODERANGE_7BIT)) {
|
|
827
835
|
return true;
|
|
@@ -834,12 +842,8 @@ static inline bool valid_json_string_p(VALUE str)
|
|
|
834
842
|
return false;
|
|
835
843
|
}
|
|
836
844
|
|
|
837
|
-
static
|
|
845
|
+
NOINLINE(static) VALUE convert_invalid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
|
|
838
846
|
{
|
|
839
|
-
if (RB_LIKELY(valid_json_string_p(str))) {
|
|
840
|
-
return str;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
847
|
if (!as_json_called && data->state->strict && RTEST(data->state->as_json)) {
|
|
844
848
|
VALUE coerced_str = json_call_as_json(data->state, str, Qfalse);
|
|
845
849
|
if (coerced_str != str) {
|
|
@@ -875,6 +879,16 @@ static inline VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE
|
|
|
875
879
|
return rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
|
876
880
|
}
|
|
877
881
|
|
|
882
|
+
ALWAYS_INLINE(static) VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
|
|
883
|
+
{
|
|
884
|
+
if (RB_LIKELY(valid_json_string_p(str))) {
|
|
885
|
+
return str;
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
return convert_invalid_encoding(data, str, as_json_called, is_key);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
878
892
|
static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
879
893
|
{
|
|
880
894
|
fbuffer_append_char(buffer, '"');
|
|
@@ -893,7 +907,7 @@ static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data
|
|
|
893
907
|
search.chunk_end = NULL;
|
|
894
908
|
#endif /* HAVE_SIMD */
|
|
895
909
|
|
|
896
|
-
switch (
|
|
910
|
+
switch (json_str_coderange(obj)) {
|
|
897
911
|
case ENC_CODERANGE_7BIT:
|
|
898
912
|
case ENC_CODERANGE_VALID:
|
|
899
913
|
if (RB_UNLIKELY(data->state->ascii_only)) {
|
|
@@ -364,6 +364,7 @@ typedef struct JSON_ParserStateStruct {
|
|
|
364
364
|
rvalue_cache name_cache;
|
|
365
365
|
int in_array;
|
|
366
366
|
int current_nesting;
|
|
367
|
+
unsigned int emitted_deprecations;
|
|
367
368
|
} JSON_ParserState;
|
|
368
369
|
|
|
369
370
|
static inline size_t rest(JSON_ParserState *state) {
|
|
@@ -945,7 +946,12 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
|
|
|
945
946
|
case JSON_IGNORE:
|
|
946
947
|
break;
|
|
947
948
|
case JSON_DEPRECATED:
|
|
948
|
-
|
|
949
|
+
// Only emit the first few deprecations to avoid spamming.
|
|
950
|
+
if (state->emitted_deprecations < 5) {
|
|
951
|
+
emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
|
|
952
|
+
state->emitted_deprecations++;
|
|
953
|
+
}
|
|
954
|
+
|
|
949
955
|
break;
|
|
950
956
|
case JSON_RAISE:
|
|
951
957
|
raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
|
|
@@ -1465,9 +1471,22 @@ static VALUE convert_encoding(VALUE source)
|
|
|
1465
1471
|
return rb_funcall(source, i_encode, 1, Encoding_UTF_8);
|
|
1466
1472
|
}
|
|
1467
1473
|
|
|
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
|
+
|
|
1468
1485
|
static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1469
1486
|
{
|
|
1470
|
-
|
|
1487
|
+
struct parser_config_init_args *args = (struct parser_config_init_args *)data;
|
|
1488
|
+
JSON_ParserConfig *config = args->config;
|
|
1489
|
+
VALUE self = args->self;
|
|
1471
1490
|
|
|
1472
1491
|
if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
|
|
1473
1492
|
else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
|
|
@@ -1476,15 +1495,15 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1476
1495
|
else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
|
|
1477
1496
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
|
1478
1497
|
else if (key == sym_freeze) { config->freeze = RTEST(val); }
|
|
1479
|
-
else if (key == sym_on_load) { config->on_load_proc
|
|
1498
|
+
else if (key == sym_on_load) { parser_config_wb_write(self, &config->on_load_proc, RTEST(val) ? val : Qfalse); }
|
|
1480
1499
|
else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
|
|
1481
1500
|
else if (key == sym_decimal_class) {
|
|
1482
1501
|
if (RTEST(val)) {
|
|
1483
1502
|
if (rb_respond_to(val, i_try_convert)) {
|
|
1484
|
-
config->decimal_class
|
|
1503
|
+
parser_config_wb_write(self, &config->decimal_class, val);
|
|
1485
1504
|
config->decimal_method_id = i_try_convert;
|
|
1486
1505
|
} else if (rb_respond_to(val, i_new)) {
|
|
1487
|
-
config->decimal_class
|
|
1506
|
+
parser_config_wb_write(self, &config->decimal_class, val);
|
|
1488
1507
|
config->decimal_method_id = i_new;
|
|
1489
1508
|
} else if (RB_TYPE_P(val, T_CLASS)) {
|
|
1490
1509
|
VALUE name = rb_class_name(val);
|
|
@@ -1493,7 +1512,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1493
1512
|
if (last_colon) {
|
|
1494
1513
|
const char *mod_path_end = last_colon - 1;
|
|
1495
1514
|
VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
|
|
1496
|
-
config->decimal_class
|
|
1515
|
+
parser_config_wb_write(self, &config->decimal_class, rb_path_to_class(mod_path));
|
|
1497
1516
|
|
|
1498
1517
|
const char *method_name_beg = last_colon + 1;
|
|
1499
1518
|
long before_len = method_name_beg - name_cstr;
|
|
@@ -1501,7 +1520,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1501
1520
|
VALUE method_name = rb_str_substr(name, before_len, len);
|
|
1502
1521
|
config->decimal_method_id = SYM2ID(rb_str_intern(method_name));
|
|
1503
1522
|
} else {
|
|
1504
|
-
config->decimal_class
|
|
1523
|
+
parser_config_wb_write(self, &config->decimal_class, rb_mKernel);
|
|
1505
1524
|
config->decimal_method_id = SYM2ID(rb_str_intern(name));
|
|
1506
1525
|
}
|
|
1507
1526
|
}
|
|
@@ -1511,16 +1530,21 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1511
1530
|
return ST_CONTINUE;
|
|
1512
1531
|
}
|
|
1513
1532
|
|
|
1514
|
-
static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1533
|
+
static void parser_config_init(JSON_ParserConfig *config, VALUE opts, VALUE self)
|
|
1515
1534
|
{
|
|
1516
1535
|
config->max_nesting = 100;
|
|
1517
1536
|
|
|
1537
|
+
struct parser_config_init_args args = {
|
|
1538
|
+
.config = config,
|
|
1539
|
+
.self = self,
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1518
1542
|
if (!NIL_P(opts)) {
|
|
1519
1543
|
Check_Type(opts, T_HASH);
|
|
1520
1544
|
if (RHASH_SIZE(opts) > 0) {
|
|
1521
1545
|
// We assume in most cases few keys are set so it's faster to go over
|
|
1522
1546
|
// the provided keys than to check all possible keys.
|
|
1523
|
-
rb_hash_foreach(opts, parser_config_init_i, (VALUE)
|
|
1547
|
+
rb_hash_foreach(opts, parser_config_init_i, (VALUE)&args);
|
|
1524
1548
|
}
|
|
1525
1549
|
|
|
1526
1550
|
}
|
|
@@ -1554,9 +1578,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
|
|
|
1554
1578
|
rb_check_frozen(self);
|
|
1555
1579
|
GET_PARSER_CONFIG;
|
|
1556
1580
|
|
|
1557
|
-
parser_config_init(config, opts);
|
|
1558
|
-
|
|
1559
|
-
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
|
|
1581
|
+
parser_config_init(config, opts, self);
|
|
1560
1582
|
|
|
1561
1583
|
return self;
|
|
1562
1584
|
}
|
|
@@ -1618,7 +1640,7 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
|
|
|
1618
1640
|
|
|
1619
1641
|
JSON_ParserConfig _config = {0};
|
|
1620
1642
|
JSON_ParserConfig *config = &_config;
|
|
1621
|
-
parser_config_init(config, opts);
|
|
1643
|
+
parser_config_init(config, opts, false);
|
|
1622
1644
|
|
|
1623
1645
|
return cParser_parse(config, Vsource);
|
|
1624
1646
|
}
|
data/lib/json/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.19.
|
|
4
|
+
version: 2.19.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Frank
|
|
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
84
|
- !ruby/object:Gem::Version
|
|
85
85
|
version: '0'
|
|
86
86
|
requirements: []
|
|
87
|
-
rubygems_version: 4.0.
|
|
87
|
+
rubygems_version: 4.0.10
|
|
88
88
|
specification_version: 4
|
|
89
89
|
summary: JSON Implementation for Ruby
|
|
90
90
|
test_files: []
|