oj 3.17.1 → 3.17.3

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: a7515f34ac9c85f3e60f14c886bf3701f41fd077bdc518c71c6125e6ca7913db
4
- data.tar.gz: f4a5cab57b8fc728e7ec4aac4dbc672d26b69f83f6aa31c98c6d6237892f6bdc
3
+ metadata.gz: e7458dcdf494ef6b1b283ca86d51fba0b3102ecf5cec13f43682878c01708c80
4
+ data.tar.gz: ab8099b8b275aa5acab45a012bbc96ef0c860e041be2c4ae7d6f7cd331da1755
5
5
  SHA512:
6
- metadata.gz: 0aa115483a049bb1a9b406d3d9fa1dda4dcb47cf50236301f5ea9acca4c21b20118a027462e384d60c0cb287be92a80b163dc924f58a93a0f5998d0f2e577f4c
7
- data.tar.gz: 2f31c241a2283f353bf503eb54d89921643ec5fdc0ecb8166c31d68b5deb79fb26f68ea412155cc17dc5734bce9a85451bd798c600365428d5f389eabdc41346
6
+ metadata.gz: 60d445fd27bbea120359c21d0c1b0ac1d4fbbd678c8fd28efe620706d382a2f0cc434645967c9bac0b6d08d1065fe99dc4b15e2623d98ca0e15a61eb591a993b
7
+ data.tar.gz: b7736fd3a7b27f98ef3e4df05464000849403ff33a3f82ecd6d8c51b40d0c2753d23ed14c078eb26506d504de991e35ebe68e5703225c80aab6ebbd28b7a80dc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.17.3 - 2026-06-04
4
+
5
+ - Fixed issue in intern.c and fast.c.
6
+
7
+ ## 3.17.2 - 2026-05-27
8
+
9
+ - Fixed multiple issues related to extreme sizes.
10
+
3
11
  ## 3.17.1 - 2026-05-15
4
12
 
5
13
  - Fixed "quoted string not terminated" error.
data/ext/oj/compat.c CHANGED
@@ -27,7 +27,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
27
27
  volatile VALUE rkey = oj_calc_hash_key(pi, kval);
28
28
 
29
29
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
30
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
30
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
31
31
 
32
32
  if (Qnil != clas) {
33
33
  rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
@@ -84,7 +84,7 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
84
84
  volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
85
85
 
86
86
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
87
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
87
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
88
88
 
89
89
  if (Qnil != clas) {
90
90
  pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
@@ -155,7 +155,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
155
155
  volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
156
156
 
157
157
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
158
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
158
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
159
159
 
160
160
  if (Qnil != clas) {
161
161
  rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
data/ext/oj/custom.c CHANGED
@@ -915,7 +915,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
915
915
  volatile VALUE rkey = oj_calc_hash_key(pi, kval);
916
916
 
917
917
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
918
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
918
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
919
919
 
920
920
  if (Qnil != clas) {
921
921
  rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
@@ -1020,7 +1020,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
1020
1020
  volatile VALUE rstr = rb_utf8_str_new(str, len);
1021
1021
 
1022
1022
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
1023
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
1023
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, len);
1024
1024
 
1025
1025
  if (Qnil != clas) {
1026
1026
  rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
data/ext/oj/fast.c CHANGED
@@ -80,7 +80,7 @@ static void each_leaf(Doc doc, VALUE self);
80
80
  static int move_step(Doc doc, const char *path, int loc);
81
81
  static Leaf get_doc_leaf(Doc doc, const char *path);
82
82
  static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
83
- static void each_value(Doc doc, Leaf leaf);
83
+ static void each_value(Doc doc, Leaf leaf, VALUE self);
84
84
 
85
85
  VALUE oj_doc_class = Qundef;
86
86
 
@@ -957,6 +957,9 @@ static void each_leaf(Doc doc, VALUE self) {
957
957
  }
958
958
  } else {
959
959
  rb_yield(self);
960
+ if (NULL == DATA_PTR(self)) {
961
+ rb_raise(rb_eIOError, "Document closed.");
962
+ }
960
963
  }
961
964
  }
962
965
 
@@ -1050,19 +1053,22 @@ static int move_step(Doc doc, const char *path, int loc) {
1050
1053
  return loc;
1051
1054
  }
1052
1055
 
1053
- static void each_value(Doc doc, Leaf leaf) {
1056
+ static void each_value(Doc doc, Leaf leaf, VALUE self) {
1054
1057
  if (COL_VAL == leaf->value_type) {
1055
1058
  if (0 != leaf->elements) {
1056
1059
  Leaf first = leaf->elements->next;
1057
1060
  Leaf e = first;
1058
1061
 
1059
1062
  do {
1060
- each_value(doc, e);
1063
+ each_value(doc, e, self);
1061
1064
  e = e->next;
1062
1065
  } while (e != first);
1063
1066
  }
1064
1067
  } else {
1065
1068
  rb_yield(leaf_value(doc, leaf));
1069
+ if (NULL == DATA_PTR(self)) {
1070
+ rb_raise(rb_eIOError, "Document closed.");
1071
+ }
1066
1072
  }
1067
1073
  }
1068
1074
 
@@ -1498,12 +1504,19 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1498
1504
  Leaf first = (*doc->where)->elements->next;
1499
1505
  Leaf e = first;
1500
1506
 
1507
+ if (MAX_STACK <= (doc->where + 1) - doc->where_path) {
1508
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
1509
+ }
1501
1510
  doc->where++;
1502
1511
  do {
1503
1512
  *doc->where = e;
1504
1513
  rb_yield(self);
1514
+ if (NULL == DATA_PTR(self)) {
1515
+ rb_raise(rb_eIOError, "Document closed.");
1516
+ }
1505
1517
  e = e->next;
1506
1518
  } while (e != first);
1519
+ doc->where--;
1507
1520
  }
1508
1521
  if (0 < wlen) {
1509
1522
  memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
@@ -1547,7 +1560,7 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1547
1560
  path = StringValuePtr(*argv);
1548
1561
  }
1549
1562
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1550
- each_value(doc, leaf);
1563
+ each_value(doc, leaf, self);
1551
1564
  }
1552
1565
  }
1553
1566
  return Qnil;
data/ext/oj/intern.c CHANGED
@@ -69,7 +69,7 @@ static VALUE form_attr(const char *str, size_t len) {
69
69
  memcpy(b + 1, str, len);
70
70
  b[len + 1] = '\0';
71
71
  }
72
- id = rb_intern3(buf, len + 1, oj_utf8_encoding);
72
+ id = rb_intern3(b, len + 1, oj_utf8_encoding);
73
73
  OJ_R_FREE(b);
74
74
  return id;
75
75
  }
data/ext/oj/oj.c CHANGED
@@ -20,6 +20,8 @@
20
20
  #include "rails.h"
21
21
  #include "simd.h"
22
22
 
23
+ #define MAX_INDENT 16
24
+
23
25
  typedef struct _yesNoOpt {
24
26
  VALUE sym;
25
27
  char *attr;
@@ -766,7 +768,10 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
766
768
  case T_FIXNUM:
767
769
  copts->dump_opts.indent_size = 0;
768
770
  *copts->dump_opts.indent_str = '\0';
769
- copts->indent = FIX2INT(v);
771
+ if (MAX_INDENT < FIX2INT(v)) {
772
+ rb_raise(rb_eArgError, "indent is limited to %d characters.", MAX_INDENT);
773
+ }
774
+ copts->indent = FIX2INT(v);
770
775
  break;
771
776
  case T_STRING:
772
777
  if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
data/ext/oj/parse.c CHANGED
@@ -394,7 +394,7 @@ void oj_scanner_init(void) {
394
394
  static void read_escaped_str(ParseInfo pi, const char *start) {
395
395
  struct _buf buf;
396
396
  const char *s;
397
- int cnt = (int)(pi->cur - start);
397
+ size_t cnt = pi->cur - start;
398
398
  uint32_t code;
399
399
  Val parent = stack_peek(&pi->stack);
400
400
 
@@ -669,7 +669,7 @@ static void read_num(ParseInfo pi) {
669
669
  // A trailing . is not a valid decimal but if encountered allow it
670
670
  // except when mimicking the JSON gem or in strict mode.
671
671
  if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) {
672
- int pos = (int)(pi->cur - ni.str);
672
+ size_t pos = pi->cur - ni.str;
673
673
 
674
674
  if (1 == pos || (2 == pos && ni.neg)) {
675
675
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
data/ext/oj/parser.c CHANGED
@@ -674,6 +674,10 @@ static void parse(ojParser p, const byte *json, bool more) {
674
674
  p->cur = b - json;
675
675
  p->funcs[p->stack[p->depth]].open_object(p);
676
676
  p->depth++;
677
+ if ((int)sizeof(p->stack) <= p->depth) {
678
+ parse_error(p, "too deeply nested");
679
+ break;
680
+ }
677
681
  p->stack[p->depth] = OBJECT_FUN;
678
682
  p->map = key1_map;
679
683
  break;
@@ -696,6 +700,10 @@ static void parse(ojParser p, const byte *json, bool more) {
696
700
  p->cur = b - json;
697
701
  p->funcs[p->stack[p->depth]].open_array(p);
698
702
  p->depth++;
703
+ if ((int)sizeof(p->stack) <= p->depth) {
704
+ parse_error(p, "too deeply nested");
705
+ break;
706
+ }
699
707
  p->stack[p->depth] = ARRAY_FUN;
700
708
  p->map = value_map;
701
709
  break;
@@ -1399,14 +1407,19 @@ static void validate_document_end(ojParser p) {
1399
1407
  */
1400
1408
  static VALUE parser_parse(VALUE self, VALUE json) {
1401
1409
  ojParser p;
1402
- const byte *ptr = (const byte *)StringValuePtr(json);
1410
+ int frozen = OBJ_FROZEN(json);
1411
+ const byte *ptr;
1412
+
1413
+ if (!frozen) {
1414
+ rb_str_freeze(json);
1415
+ }
1416
+ ptr = (const byte *)StringValuePtr(json);
1403
1417
 
1404
1418
  TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1405
1419
 
1406
1420
  parser_reset(p);
1407
1421
  p->start(p);
1408
1422
  parse(p, ptr, false);
1409
-
1410
1423
  validate_document_end(p);
1411
1424
 
1412
1425
  return p->result(p);
data/ext/oj/rxclass.c CHANGED
@@ -96,7 +96,7 @@ int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
96
96
  }
97
97
 
98
98
  VALUE
99
- oj_rxclass_match(RxClass rc, const char *str, int len) {
99
+ oj_rxclass_match(RxClass rc, const char *str, size_t len) {
100
100
  RxC rxc;
101
101
  char buf[4096];
102
102
 
data/ext/oj/rxclass.h CHANGED
@@ -19,7 +19,7 @@ typedef struct _rxClass {
19
19
  extern void oj_rxclass_init(RxClass rc);
20
20
  extern void oj_rxclass_cleanup(RxClass rc);
21
21
  extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas);
22
- extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len);
22
+ extern VALUE oj_rxclass_match(RxClass rc, const char *str, size_t len);
23
23
  extern void oj_rxclass_copy(RxClass src, RxClass dest);
24
24
  extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
25
25
 
data/ext/oj/safe.c CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  #include "safe.h"
2
3
 
3
4
  static VALUE max_hash_size_sym, max_array_size_sym, max_depth_sym, max_total_elements_sym, max_hash_size_error_class,
data/ext/oj/usual.c CHANGED
@@ -63,7 +63,7 @@ static VALUE form_attr(const char *str, size_t len) {
63
63
  memcpy(b + 1, str, len);
64
64
  b[len + 1] = '\0';
65
65
 
66
- id = rb_intern3(buf, len + 1, oj_utf8_encoding);
66
+ id = rb_intern3(b, len + 1, oj_utf8_encoding);
67
67
  OJ_R_FREE(b);
68
68
  return id;
69
69
  }
@@ -200,7 +200,10 @@ static void push_key(ojParser p) {
200
200
  d->ktail = d->khead + pos;
201
201
  d->kend = d->khead + cap;
202
202
  }
203
- d->ktail->len = klen;
203
+ if (32000 < klen) {
204
+ rb_raise(oj_json_parser_error_class, "Key too long. Keys are limited to 32,000 bytes.");
205
+ }
206
+ d->ktail->len = (int16_t)klen;
204
207
  if (klen < sizeof(d->ktail->buf)) {
205
208
  memcpy(d->ktail->buf, key, klen);
206
209
  d->ktail->buf[klen] = '\0';
@@ -608,12 +611,16 @@ static void dfree(ojParser p) {
608
611
  Usual d = (Usual)p->ctx;
609
612
 
610
613
  cache_free(d->str_cache);
614
+ d->str_cache = NULL;
611
615
  cache_free(d->attr_cache);
616
+ d->attr_cache = NULL;
612
617
  if (NULL != d->sym_cache) {
613
618
  cache_free(d->sym_cache);
619
+ d->sym_cache = NULL;
614
620
  }
615
621
  if (NULL != d->class_cache) {
616
622
  cache_free(d->class_cache);
623
+ d->class_cache = NULL;
617
624
  }
618
625
  OJ_R_FREE(d->vhead);
619
626
  OJ_R_FREE(d->chead);
@@ -640,6 +647,12 @@ static void mark(ojParser p) {
640
647
  if (NULL != d->class_cache) {
641
648
  cache_mark(d->class_cache);
642
649
  }
650
+ if (Qnil != d->hash_class) {
651
+ rb_gc_mark(d->hash_class);
652
+ }
653
+ if (Qnil != d->array_class) {
654
+ rb_gc_mark(d->array_class);
655
+ }
643
656
  for (vp = d->vhead; vp < d->vtail; vp++) {
644
657
  if (Qundef != *vp) {
645
658
  rb_gc_mark(*vp);
@@ -1050,10 +1063,10 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1050
1063
  if (NULL != d->sym_cache) {
1051
1064
  cache_free(d->sym_cache);
1052
1065
  d->sym_cache = NULL;
1066
+ d->key_cache = NULL;
1053
1067
  }
1054
- if (!d->cache_keys) {
1055
- d->get_key = str_key;
1056
- }
1068
+ d->cache_keys = false;
1069
+ d->get_key = str_key;
1057
1070
  }
1058
1071
  return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1059
1072
  }
data/lib/oj/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Oj
2
2
  # Current version of the module.
3
- VERSION = '3.17.1'
3
+ VERSION = '3.17.3'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oj
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.17.1
4
+ version: 3.17.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
@@ -231,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
231
  - !ruby/object:Gem::Version
232
232
  version: '0'
233
233
  requirements: []
234
- rubygems_version: 4.0.6
234
+ rubygems_version: 4.0.3
235
235
  specification_version: 4
236
236
  summary: A fast JSON parser and serializer.
237
237
  test_files: []