json 2.18.1 → 2.19.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb2890db4c527125d27bc7c21fc64d3ac532ffbec8080f89a678daf48c36e09e
4
- data.tar.gz: c4b37d085d05d3c43df97b3c24898dc6be61c76ba64c749b5a8a86bf4fc1198d
3
+ metadata.gz: 579bc938143b2fc703d90623fb985af883a7b46f0641d874cc44a39a4ffae2dd
4
+ data.tar.gz: f69a8d12a9f83378e0e0e6b0abdda34cf23d7ebf026dcc114dc70089dd159190
5
5
  SHA512:
6
- metadata.gz: fb55ef5a0aa6961ef0fe3bb30f398834820357045ad27a8fdb7e53eaba3af7c4d356ef26c0e73b7a87d2d9d51e500eae7193d7d1ae3aa1058c7973bcc462674b
7
- data.tar.gz: bfb499789bbcee7f5f8d67e32ded664dc62c632ae39fe80bf4bff3d6aec16eee3730a7c4883216a393326f2ab33e94e5f9c58da4c5b31627347108c36c2b211c
6
+ metadata.gz: 3bb0a35502ac84a22a71f076a68feb5ea525ff802491e2532bd863653d1b6808de4715108886e6bb00cc5ef378ec298bea81e2d932a748886f1f4ec8b0637b03
7
+ data.tar.gz: e50b9b31f846e105a725807db54fe86f8176331d975ea772a1f9f666ed91e4555497f79008a4b01b08de3c2605cb1867671f87b86f196632b05d1f5a21872143
data/CHANGES.md CHANGED
@@ -2,6 +2,43 @@
2
2
 
3
3
  ### Unreleased
4
4
 
5
+ ### 2026-05-28 (2.19.7)
6
+
7
+ * Fix some more edge cases with out of range floats.
8
+ * Ensure the string provided to `JSON.parse` can't be mutated during parsing.
9
+ * Add missing write barriers in `State#dup`.
10
+ * Further validate generator `depth` config.
11
+
12
+ ### 2026-05-28 (2.19.6)
13
+
14
+ * Cleanly handle overly large `depth` generator argument.
15
+ * Add missing write barrier in `ParserConfig`.
16
+
17
+ ### 2026-05-04 (2.19.5)
18
+
19
+ * Cap the parser to emit a maximum of 5 deprecation warnings per document. Emitting more is not helpful.
20
+
21
+ ### 2026-04-19 (2.19.4)
22
+
23
+ * Fix parsing of out of range floats (very large exponents that lead to either `0.0` or `Inf`).
24
+
25
+ ### 2026-03-25 (2.19.3)
26
+
27
+ * Fix handling of unescaped control characters preceeded by a backslash.
28
+
29
+ ### 2026-03-18 (2.19.2)
30
+
31
+ * Fix a format string injection vulnerability in `JSON.parse(doc, allow_duplicate_key: false)`. `CVE-2026-33210`.
32
+
33
+ ### 2026-03-08 (2.19.1)
34
+
35
+ * Fix a compiler dependent GC bug introduced in `2.18.0`.
36
+
37
+ ### 2026-03-06 (2.19.0)
38
+
39
+ * Fix `allow_blank` parsing option to no longer allow invalid types (e.g. `load([], allow_blank: true)` now raise a type error).
40
+ * Add `allow_invalid_escape` parsing option to ignore backslashes that aren't followed by one of the valid escape characters.
41
+
5
42
  ### 2026-02-03 (2.18.1)
6
43
 
7
44
  * Fix a potential crash in very specific circumstance if GC triggers during a call to `to_json`
@@ -11,6 +48,10 @@
11
48
 
12
49
  * Add `:allow_control_characters` parser options, to allow JSON strings containing unescaped ASCII control characters (e.g. newlines).
13
50
 
51
+ ### 2026-03-18 (2.17.1.2) - Security Backport
52
+
53
+ * Fix a format string injection vulnerability in `JSON.parse(doc, allow_duplicate_key: false)`. `CVE-2026-33210`.
54
+
14
55
  ### 2025-12-04 (2.17.1)
15
56
 
16
57
  * Fix a regression in parsing of unicode surogate pairs (`\uXX\uXX`) that could cause an invalid string to be returned.
@@ -37,6 +78,10 @@
37
78
  * Optimized numbers parsing using SWAR (thanks to Scott Myron).
38
79
  * Optimized parsing of pretty printed documents using SWAR (thanks to Scott Myron).
39
80
 
81
+ ### 2026-03-18 (2.15.2.1) - Security Backport
82
+
83
+ * Fix a format string injection vulnerability in `JSON.parse(doc, allow_duplicate_key: false)`. `CVE-2026-33210`.
84
+
40
85
  ### 2025-10-25 (2.15.2)
41
86
 
42
87
  * Fix `JSON::Coder` to have one dedicated depth counter per invocation.
@@ -11,11 +11,11 @@ enum fbuffer_type {
11
11
 
12
12
  typedef struct FBufferStruct {
13
13
  enum fbuffer_type type;
14
- unsigned long initial_length;
15
- unsigned long len;
16
- unsigned long capa;
14
+ size_t initial_length;
15
+ size_t len;
16
+ size_t capa;
17
17
  #if JSON_DEBUG
18
- unsigned long requested;
18
+ size_t requested;
19
19
  #endif
20
20
  char *ptr;
21
21
  VALUE io;
@@ -32,12 +32,12 @@ typedef struct FBufferStruct {
32
32
 
33
33
  static void fbuffer_free(FBuffer *fb);
34
34
  static void fbuffer_clear(FBuffer *fb);
35
- static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
35
+ static void fbuffer_append(FBuffer *fb, const char *newstr, size_t len);
36
36
  static void fbuffer_append_long(FBuffer *fb, long number);
37
37
  static inline void fbuffer_append_char(FBuffer *fb, char newchr);
38
38
  static VALUE fbuffer_finalize(FBuffer *fb);
39
39
 
40
- static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
40
+ static void fbuffer_stack_init(FBuffer *fb, size_t initial_length, char *stack_buffer, size_t stack_buffer_size)
41
41
  {
42
42
  fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
43
43
  if (stack_buffer) {
@@ -50,7 +50,7 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
50
50
  #endif
51
51
  }
52
52
 
53
- static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
53
+ static inline void fbuffer_consumed(FBuffer *fb, size_t consumed)
54
54
  {
55
55
  #if JSON_DEBUG
56
56
  if (consumed > fb->requested) {
@@ -79,7 +79,7 @@ static void fbuffer_flush(FBuffer *fb)
79
79
  fbuffer_clear(fb);
80
80
  }
81
81
 
82
- static void fbuffer_realloc(FBuffer *fb, unsigned long required)
82
+ static void fbuffer_realloc(FBuffer *fb, size_t required)
83
83
  {
84
84
  if (required > fb->capa) {
85
85
  if (fb->type == FBUFFER_STACK_ALLOCATED) {
@@ -94,7 +94,7 @@ static void fbuffer_realloc(FBuffer *fb, unsigned long required)
94
94
  }
95
95
  }
96
96
 
97
- static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
97
+ static void fbuffer_do_inc_capa(FBuffer *fb, size_t requested)
98
98
  {
99
99
  if (RB_UNLIKELY(fb->io)) {
100
100
  if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
@@ -108,7 +108,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
108
108
  }
109
109
  }
110
110
 
111
- unsigned long required;
111
+ size_t required;
112
112
 
113
113
  if (RB_UNLIKELY(!fb->ptr)) {
114
114
  fb->ptr = ALLOC_N(char, fb->initial_length);
@@ -120,7 +120,7 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
120
120
  fbuffer_realloc(fb, required);
121
121
  }
122
122
 
123
- static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
123
+ static inline void fbuffer_inc_capa(FBuffer *fb, size_t requested)
124
124
  {
125
125
  #if JSON_DEBUG
126
126
  fb->requested = requested;
@@ -131,13 +131,22 @@ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
131
131
  }
132
132
  }
133
133
 
134
- static inline void fbuffer_append_reserved(FBuffer *fb, const char *newstr, unsigned long len)
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
+
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);
137
146
  fbuffer_consumed(fb, len);
138
147
  }
139
148
 
140
- static inline void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
149
+ static inline void fbuffer_append(FBuffer *fb, const char *newstr, size_t len)
141
150
  {
142
151
  if (len > 0) {
143
152
  fbuffer_inc_capa(fb, len);
@@ -162,19 +171,20 @@ static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
162
171
  static void fbuffer_append_str(FBuffer *fb, VALUE str)
163
172
  {
164
173
  const char *ptr;
165
- unsigned long len;
174
+ size_t len;
166
175
  RSTRING_GETMEM(str, ptr, len);
167
176
 
168
177
  fbuffer_append(fb, ptr, len);
178
+ RB_GC_GUARD(str);
169
179
  }
170
180
 
171
181
  static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
172
182
  {
173
183
  const char *ptr;
174
- unsigned long len;
184
+ size_t len;
175
185
  RSTRING_GETMEM(str, ptr, len);
176
186
 
177
- fbuffer_inc_capa(fb, repeat * len);
187
+ fbuffer_inc_capa(fb, fbuffer_size_mul_or_raise(repeat, len));
178
188
  while (repeat) {
179
189
  #if JSON_DEBUG
180
190
  fb->requested = len;
@@ -182,6 +192,7 @@ static void fbuffer_append_str_repeat(FBuffer *fb, VALUE str, size_t repeat)
182
192
  fbuffer_append_reserved(fb, ptr, len);
183
193
  repeat--;
184
194
  }
195
+ RB_GC_GUARD(str);
185
196
  }
186
197
 
187
198
  static inline void fbuffer_append_char(FBuffer *fb, char newchr)
@@ -5,6 +5,8 @@ if RUBY_ENGINE == 'truffleruby'
5
5
  File.write('Makefile', dummy_makefile("").join)
6
6
  else
7
7
  append_cflags("-std=c99")
8
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
9
+
8
10
  $defs << "-DJSON_GENERATOR"
9
11
  $defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
10
12