json 2.10.1 → 2.10.2

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: fc08bd5e3c83c4e731d37e18b5a32f9bf0049d896c483f1beb96af96f2daad18
4
- data.tar.gz: ff215943fdccc5a5ed3f7390719aa5c43a18664e19f86d94226ff14c154cc354
3
+ metadata.gz: b909ed90787afa31835c9926529808ca3c6b161755e1f6126b7fe203231fa0c2
4
+ data.tar.gz: efd6a873e98f9e4b2b8c078210f141dfde5f3773884bd5851f228c184ff94ff7
5
5
  SHA512:
6
- metadata.gz: e3bc85653be385e76842fa3f69671fccdc4235a32806f554cf8ec4a9ad697996be97d3aef52823b3c1f8839e1cd9a7893ab87360ca76d59b4ff704c75fcb655e
7
- data.tar.gz: f2f09188afd38972e15e1c80c2c8c4efd14aee954d18ff83d4a6a993bd0f9d9c84362232c17abbc9bf3ffdfce062c79c75a6fccf124bdbd3345a202b76d50a26
6
+ metadata.gz: bff39363d5d7fa2f209d5bf97a5728738058bc83600b732d95487e263a5a3901b1e18d5c42d7d2be019ac55ef069a50cedc1d9a8d22b11e6061f2eef747dc94d
7
+ data.tar.gz: 693e480f8f2489e26c43eef56ad8977ab3f00fada03318a48b88ac55e2b82b15ffae92fd05dd47d86686fae39169b079f59a68fffc6efaf44ee3503a45060e30
data/CHANGES.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changes
2
2
 
3
+ ### 2025-03-12 (2.10.2)
4
+
5
+ * Fix a potential crash in the C extension parser.
6
+ * Raise a ParserError on all incomplete unicode escape sequence. This was the behavior until `2.10.0` unadvertently changed it.
7
+ * Ensure document snippets that are included in parser errors don't include truncated multibyte characters.
8
+
3
9
  ### 2025-02-10 (2.10.1)
4
10
 
5
11
  * Fix a compatibility issue with `MultiJson.dump(obj, pretty: true)`: `no implicit conversion of false into Proc (TypeError)`.
@@ -341,6 +341,44 @@ static void rvalue_stack_eagerly_release(VALUE handle)
341
341
  }
342
342
  }
343
343
 
344
+
345
+ #ifndef HAVE_STRNLEN
346
+ static size_t strnlen(const char *s, size_t maxlen)
347
+ {
348
+ char *p;
349
+ return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen);
350
+ }
351
+ #endif
352
+
353
+ #define PARSE_ERROR_FRAGMENT_LEN 32
354
+ #ifdef RBIMPL_ATTR_NORETURN
355
+ RBIMPL_ATTR_NORETURN()
356
+ #endif
357
+ static void raise_parse_error(const char *format, const char *start)
358
+ {
359
+ unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
360
+
361
+ size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
362
+ const char *ptr = start;
363
+
364
+ if (len == PARSE_ERROR_FRAGMENT_LEN) {
365
+ MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
366
+
367
+ while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
368
+ len--;
369
+ }
370
+
371
+ if (buffer[len - 1] >= 0xC0) { // multibyte character start
372
+ len--;
373
+ }
374
+
375
+ buffer[len] = '\0';
376
+ ptr = (const char *)buffer;
377
+ }
378
+
379
+ rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
380
+ }
381
+
344
382
  /* unicode */
345
383
 
346
384
  static const signed char digit_values[256] = {
@@ -362,21 +400,19 @@ static const signed char digit_values[256] = {
362
400
 
363
401
  static uint32_t unescape_unicode(const unsigned char *p)
364
402
  {
365
- const uint32_t replacement_char = 0xFFFD;
366
-
367
403
  signed char b;
368
404
  uint32_t result = 0;
369
405
  b = digit_values[p[0]];
370
- if (b < 0) return replacement_char;
406
+ if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
371
407
  result = (result << 4) | (unsigned char)b;
372
408
  b = digit_values[p[1]];
373
- if (b < 0) return replacement_char;
409
+ if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
374
410
  result = (result << 4) | (unsigned char)b;
375
411
  b = digit_values[p[2]];
376
- if (b < 0) return replacement_char;
412
+ if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
377
413
  result = (result << 4) | (unsigned char)b;
378
414
  b = digit_values[p[3]];
379
- if (b < 0) return replacement_char;
415
+ if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
380
416
  result = (result << 4) | (unsigned char)b;
381
417
  return result;
382
418
  }
@@ -440,34 +476,6 @@ typedef struct JSON_ParserStateStruct {
440
476
 
441
477
  static const rb_data_type_t JSON_ParserConfig_type;
442
478
 
443
- #ifndef HAVE_STRNLEN
444
- static size_t strnlen(const char *s, size_t maxlen)
445
- {
446
- char *p;
447
- return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen);
448
- }
449
- #endif
450
-
451
- #define PARSE_ERROR_FRAGMENT_LEN 32
452
- #ifdef RBIMPL_ATTR_NORETURN
453
- RBIMPL_ATTR_NORETURN()
454
- #endif
455
- static void raise_parse_error(const char *format, const char *start)
456
- {
457
- char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
458
-
459
- size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
460
- const char *ptr = start;
461
-
462
- if (len == PARSE_ERROR_FRAGMENT_LEN) {
463
- MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
464
- buffer[PARSE_ERROR_FRAGMENT_LEN] = '\0';
465
- ptr = buffer;
466
- }
467
-
468
- rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
469
- }
470
-
471
479
  static const bool whitespace[256] = {
472
480
  [' '] = 1,
473
481
  ['\t'] = 1,
@@ -600,7 +608,7 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
600
608
  buffer = RSTRING_PTR(result);
601
609
  bufferStart = buffer;
602
610
 
603
- while ((pe = memchr(pe, '\\', stringEnd - pe))) {
611
+ while (pe < stringEnd && (pe = memchr(pe, '\\', stringEnd - pe))) {
604
612
  unescape = (char *) "?";
605
613
  unescape_len = 1;
606
614
  if (pe > p) {
data/lib/json/common.rb CHANGED
@@ -152,10 +152,13 @@ module JSON
152
152
  end
153
153
 
154
154
  def detailed_message(...)
155
+ # Exception#detailed_message doesn't exist until Ruby 3.2
156
+ super_message = defined?(super) ? super : message
157
+
155
158
  if @invalid_object.nil?
156
- super
159
+ super_message
157
160
  else
158
- "#{super}\nInvalid object: #{@invalid_object.inspect}"
161
+ "#{super_message}\nInvalid object: #{@invalid_object.inspect}"
159
162
  end
160
163
  end
161
164
  end
@@ -840,7 +843,7 @@ module JSON
840
843
 
841
844
  opts = JSON.dump_default_options
842
845
  opts = opts.merge(:max_nesting => limit) if limit
843
- opts = merge_dump_options(opts, **kwargs) if kwargs
846
+ opts = opts.merge(kwargs) if kwargs
844
847
 
845
848
  begin
846
849
  State.generate(obj, opts, anIO)
@@ -854,15 +857,6 @@ module JSON
854
857
  string.encode(to, from)
855
858
  end
856
859
 
857
- def merge_dump_options(opts, strict: NOT_SET)
858
- opts = opts.merge(strict: strict) if NOT_SET != strict
859
- opts
860
- end
861
-
862
- class << self
863
- private :merge_dump_options
864
- end
865
-
866
860
  # JSON::Coder holds a parser and generator configuration.
867
861
  #
868
862
  # module MyApp
data/lib/json/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '2.10.1'
4
+ VERSION = '2.10.2'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.1
4
+ version: 2.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-10 00:00:00.000000000 Z
10
+ date: 2025-03-12 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: This is a JSON implementation as a Ruby extension in C.
13
13
  email: flori@ping.de