oj 3.16.16 → 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.
data/ext/oj/safe.c ADDED
@@ -0,0 +1,230 @@
1
+
2
+ #include "safe.h"
3
+
4
+ static VALUE max_hash_size_sym, max_array_size_sym, max_depth_sym, max_total_elements_sym, max_hash_size_error_class,
5
+ max_array_size_error_class, max_depth_error_class, max_total_elements_error_class;
6
+
7
+ static void check_object_size(safe_T safe) {
8
+ if (NIL_P(safe->max_hash_size)) {
9
+ return;
10
+ }
11
+
12
+ struct _usual usual = safe->usual;
13
+ Col current_object_location = usual.ctail - 1;
14
+
15
+ long int number_of_items_in_stack = usual.vtail - usual.vhead;
16
+ long int number_of_items_in_hash = (number_of_items_in_stack - current_object_location->vi - 1) / 2;
17
+
18
+ if (safe->max_hash_size > number_of_items_in_hash) {
19
+ return;
20
+ }
21
+
22
+ rb_raise(max_hash_size_error_class, "Too many object items!");
23
+ }
24
+
25
+ static void check_array_size(safe_T safe) {
26
+ if (NIL_P(safe->max_array_size)) {
27
+ return;
28
+ }
29
+
30
+ struct _usual usual = safe->usual;
31
+ Col current_object_location = usual.ctail - 1;
32
+
33
+ long int number_of_items_in_stack = usual.vtail - usual.vhead;
34
+ long int number_of_items_in_array = number_of_items_in_stack - current_object_location->vi - 1;
35
+
36
+ if (safe->max_array_size > number_of_items_in_array) {
37
+ return;
38
+ }
39
+
40
+ rb_raise(max_array_size_error_class, "Too many array items!");
41
+ }
42
+
43
+ static void check_max_depth(safe_T safe, ojParser p) {
44
+ if (NIL_P(safe->max_depth) || safe->max_depth >= (p->depth + 1)) {
45
+ return;
46
+ }
47
+
48
+ rb_raise(max_depth_error_class, "JSON is too deep!");
49
+ }
50
+
51
+ static void check_max_total_elements(safe_T safe) {
52
+ /*
53
+ * We check if `max_total_elements` is greater than `current_elements_count`
54
+ * (instead of greater than or equal) because top-level elements (e.g., [],
55
+ * null, true) are not counted. As a result, `current_elements_count`
56
+ * always holds one less than the actual total.
57
+ */
58
+ if (NIL_P(safe->max_total_elements) || safe->max_total_elements > safe->current_elements_count) {
59
+ return;
60
+ }
61
+
62
+ rb_raise(max_total_elements_error_class, "Too many elements!");
63
+ }
64
+
65
+ static void safe_start(ojParser p) {
66
+ safe_T safe = (safe_T)p->ctx;
67
+
68
+ safe->current_hash_size = 0;
69
+ safe->current_array_size = 0;
70
+ safe->current_elements_count = 0;
71
+
72
+ safe->delegated_start_func(p);
73
+ }
74
+
75
+ static void safe_open_object(ojParser p) {
76
+ safe_T safe = (safe_T)p->ctx;
77
+
78
+ safe->current_hash_size++;
79
+ safe->current_elements_count++;
80
+
81
+ check_array_size(safe);
82
+ check_max_depth(safe, p);
83
+ check_max_total_elements(safe);
84
+
85
+ safe->delegated_open_object_func(p);
86
+ }
87
+
88
+ static void safe_open_array(ojParser p) {
89
+ safe_T safe = (safe_T)p->ctx;
90
+
91
+ safe->current_array_size++;
92
+ safe->current_elements_count++;
93
+
94
+ check_array_size(safe);
95
+ check_max_depth(safe, p);
96
+ check_max_total_elements(safe);
97
+
98
+ safe->delegated_open_array_func(p);
99
+ }
100
+
101
+ DEFINE_DELEGATED_FUNCTION(add_null);
102
+ DEFINE_DELEGATED_FUNCTION(add_true);
103
+ DEFINE_DELEGATED_FUNCTION(add_false);
104
+ DEFINE_DELEGATED_FUNCTION(add_int);
105
+ DEFINE_DELEGATED_FUNCTION(add_float);
106
+ DEFINE_DELEGATED_FUNCTION(add_big);
107
+ DEFINE_DELEGATED_FUNCTION(add_str);
108
+
109
+ static void safe_open_object_key(ojParser p) {
110
+ safe_T safe = (safe_T)p->ctx;
111
+
112
+ safe->current_hash_size++;
113
+ safe->current_elements_count += 2;
114
+
115
+ check_object_size(safe);
116
+ check_max_depth(safe, p);
117
+ check_max_total_elements(safe);
118
+
119
+ safe->delegated_open_object_key_func(p);
120
+ }
121
+
122
+ static void safe_open_array_key(ojParser p) {
123
+ safe_T safe = (safe_T)p->ctx;
124
+
125
+ safe->current_array_size++;
126
+ safe->current_elements_count += 2;
127
+
128
+ check_object_size(safe);
129
+ check_max_depth(safe, p);
130
+ check_max_total_elements(safe);
131
+
132
+ safe->delegated_open_array_key_func(p);
133
+ }
134
+
135
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_null);
136
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_true);
137
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_false);
138
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_int);
139
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_float);
140
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_big);
141
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_str);
142
+
143
+ void oj_init_safe_parser(ojParser p, safe_T safe, VALUE options) {
144
+ // Safe parser inherits all members of usual parser
145
+ oj_init_usual(p, &safe->usual);
146
+
147
+ safe->delegated_start_func = p->start;
148
+ p->start = safe_start;
149
+
150
+ Funcs f;
151
+
152
+ // Array parser functions
153
+ f = &p->funcs[ARRAY_FUN];
154
+ safe->delegated_open_object_func = f->open_object;
155
+ f->open_object = safe_open_object;
156
+ safe->delegated_open_array_func = f->open_array;
157
+ f->open_array = safe_open_array;
158
+ // The following overrides are done for counting objects
159
+ safe->delegated_add_null_func = f->add_null;
160
+ f->add_null = safe_add_null;
161
+ safe->delegated_add_true_func = f->add_true;
162
+ f->add_true = safe_add_true;
163
+ safe->delegated_add_false_func = f->add_false;
164
+ f->add_false = safe_add_false;
165
+ safe->delegated_add_int_func = f->add_int;
166
+ f->add_int = safe_add_int;
167
+ safe->delegated_add_float_func = f->add_float;
168
+ f->add_float = safe_add_float;
169
+ safe->delegated_add_big_func = f->add_big;
170
+ f->add_big = safe_add_big;
171
+ safe->delegated_add_str_func = f->add_str;
172
+ f->add_str = safe_add_str;
173
+
174
+ // Object parser functions
175
+ f = &p->funcs[OBJECT_FUN];
176
+ safe->delegated_open_object_key_func = f->open_object;
177
+ f->open_object = safe_open_object_key;
178
+ safe->delegated_open_array_key_func = f->open_array;
179
+ f->open_array = safe_open_array_key;
180
+ // The following overrides are done for counting objects
181
+ safe->delegated_add_null_key_func = f->add_null;
182
+ f->add_null = safe_add_null_key;
183
+ safe->delegated_add_true_key_func = f->add_true;
184
+ f->add_true = safe_add_true_key;
185
+ safe->delegated_add_false_key_func = f->add_false;
186
+ f->add_false = safe_add_false_key;
187
+ safe->delegated_add_int_key_func = f->add_int;
188
+ f->add_int = safe_add_int_key;
189
+ safe->delegated_add_float_key_func = f->add_float;
190
+ f->add_float = safe_add_float_key;
191
+ safe->delegated_add_big_key_func = f->add_big;
192
+ f->add_big = safe_add_big_key;
193
+ safe->delegated_add_str_key_func = f->add_str;
194
+ f->add_str = safe_add_str_key;
195
+
196
+ SET_CONFIG(max_hash_size);
197
+ SET_CONFIG(max_array_size);
198
+ SET_CONFIG(max_depth);
199
+ SET_CONFIG(max_total_elements);
200
+ }
201
+
202
+ void oj_set_parser_safe(ojParser p, VALUE options) {
203
+ safe_T s = OJ_R_ALLOC(struct _safe_S);
204
+
205
+ oj_init_safe_parser(p, s, options);
206
+ }
207
+
208
+ void oj_safe_init(VALUE parser_class) {
209
+ VALUE validation_error_class = rb_define_class_under(parser_class, "ValidationError", rb_eRuntimeError);
210
+
211
+ max_hash_size_error_class = rb_define_class_under(parser_class, "HashSizeError", validation_error_class);
212
+ max_array_size_error_class = rb_define_class_under(parser_class, "ArraySizeError", validation_error_class);
213
+ max_depth_error_class = rb_define_class_under(parser_class, "DepthError", validation_error_class);
214
+ max_total_elements_error_class = rb_define_class_under(parser_class, "TotalElementsError", validation_error_class);
215
+
216
+ rb_gc_register_address(&max_hash_size_error_class);
217
+ rb_gc_register_address(&max_array_size_error_class);
218
+ rb_gc_register_address(&max_depth_error_class);
219
+ rb_gc_register_address(&max_total_elements_error_class);
220
+
221
+ max_hash_size_sym = ID2SYM(rb_intern("max_hash_size"));
222
+ max_array_size_sym = ID2SYM(rb_intern("max_array_size"));
223
+ max_depth_sym = ID2SYM(rb_intern("max_depth"));
224
+ max_total_elements_sym = ID2SYM(rb_intern("max_total_elements"));
225
+
226
+ rb_gc_register_address(&max_hash_size_sym);
227
+ rb_gc_register_address(&max_array_size_sym);
228
+ rb_gc_register_address(&max_depth_sym);
229
+ rb_gc_register_address(&max_total_elements_sym);
230
+ }
data/ext/oj/safe.h ADDED
@@ -0,0 +1,79 @@
1
+ #include <ruby.h>
2
+
3
+ #include "parser.h"
4
+ #include "usual.h"
5
+
6
+ #define SET_CONFIG(config_name) \
7
+ do { \
8
+ VALUE rb_##config_name = rb_hash_aref(options, config_name##_sym); \
9
+ \
10
+ if (RB_INTEGER_TYPE_P(rb_##config_name)) { \
11
+ safe->config_name = NUM2LONG(rb_##config_name); \
12
+ } else if (!NIL_P(rb_##config_name)) { \
13
+ rb_raise(rb_eArgError, "Incorrect value provided for `" #config_name "`"); \
14
+ } else { \
15
+ safe->config_name = Qnil; \
16
+ } \
17
+ } while (0);
18
+
19
+ #define DEFINE_DELEGATED_FUNCTION(function_name) \
20
+ static void safe_##function_name(ojParser p) { \
21
+ safe_T safe = (safe_T)p->ctx; \
22
+ \
23
+ safe->current_elements_count++; \
24
+ \
25
+ check_array_size(safe); \
26
+ check_max_total_elements(safe); \
27
+ \
28
+ safe->delegated_##function_name##_func(p); \
29
+ }
30
+
31
+ #define DEFINE_DELEGATED_OBJECT_FUNCTION(function_name) \
32
+ static void safe_##function_name##_key(ojParser p) { \
33
+ safe_T safe = (safe_T)p->ctx; \
34
+ \
35
+ safe->current_elements_count += 2; \
36
+ \
37
+ check_object_size(safe); \
38
+ check_max_total_elements(safe); \
39
+ \
40
+ safe->delegated_##function_name##_key_func(p); \
41
+ }
42
+
43
+ typedef struct _safe_S {
44
+ struct _usual usual;
45
+
46
+ long int max_hash_size;
47
+ long int max_array_size;
48
+ long int max_depth;
49
+ long int max_total_elements;
50
+ long int max_json_size_bytes;
51
+
52
+ long int current_hash_size;
53
+ long int current_array_size;
54
+ long int current_elements_count;
55
+
56
+ void (*delegated_start_func)(struct _ojParser *p);
57
+
58
+ // Array functions
59
+ void (*delegated_open_object_func)(struct _ojParser *p);
60
+ void (*delegated_open_array_func)(struct _ojParser *p);
61
+ void (*delegated_add_null_func)(struct _ojParser *p);
62
+ void (*delegated_add_true_func)(struct _ojParser *p);
63
+ void (*delegated_add_false_func)(struct _ojParser *p);
64
+ void (*delegated_add_int_func)(struct _ojParser *p);
65
+ void (*delegated_add_float_func)(struct _ojParser *p);
66
+ void (*delegated_add_big_func)(struct _ojParser *p);
67
+ void (*delegated_add_str_func)(struct _ojParser *p);
68
+
69
+ // Object functions
70
+ void (*delegated_open_object_key_func)(struct _ojParser *p);
71
+ void (*delegated_open_array_key_func)(struct _ojParser *p);
72
+ void (*delegated_add_null_key_func)(struct _ojParser *p);
73
+ void (*delegated_add_true_key_func)(struct _ojParser *p);
74
+ void (*delegated_add_false_key_func)(struct _ojParser *p);
75
+ void (*delegated_add_int_key_func)(struct _ojParser *p);
76
+ void (*delegated_add_float_key_func)(struct _ojParser *p);
77
+ void (*delegated_add_big_key_func)(struct _ojParser *p);
78
+ void (*delegated_add_str_key_func)(struct _ojParser *p);
79
+ } *safe_T;
data/ext/oj/saj.c CHANGED
@@ -648,8 +648,16 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
648
648
  len = lseek(fd, 0, SEEK_END);
649
649
  lseek(fd, 0, SEEK_SET);
650
650
  json = OJ_R_ALLOC_N(char, len + 1);
651
- if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
652
- rb_raise(rb_eIOError, "failed to read from IO Object.");
651
+ {
652
+ size_t total = 0;
653
+
654
+ while (total < len) {
655
+ cnt = read(fd, json + total, len - total);
656
+ if (cnt <= 0) {
657
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
658
+ }
659
+ total += cnt;
660
+ }
653
661
  }
654
662
  json[len] = '\0';
655
663
  #endif
data/ext/oj/simd.h CHANGED
@@ -191,4 +191,29 @@ static inline OJ_TARGET_SSE42 __m128i vector_lookup_sse42(__m128i input, __m128i
191
191
 
192
192
  #endif
193
193
 
194
+ #ifndef __has_builtin
195
+ #define __has_builtin(x) 0
196
+ #endif
197
+
198
+ #if __has_builtin(__builtin_memcpy)
199
+ #define HAVE_FAST_MEMCPY 1
200
+
201
+ inline static void fast_memcpy16(void *dest, const void *src, size_t n) {
202
+ char *d = (char *)dest;
203
+ char *s = (char *)src;
204
+ if (n >= 8) {
205
+ __builtin_memcpy(d, s, 8);
206
+ __builtin_memcpy(d + n - 8, s + n - 8, 8);
207
+ } else if (n >= 4) {
208
+ __builtin_memcpy(d, s, 4);
209
+ __builtin_memcpy(d + n - 4, s + n - 4, 4);
210
+ } else if (n >= 2) {
211
+ __builtin_memcpy(d, s, 2);
212
+ __builtin_memcpy(d + n - 2, s + n - 2, 2);
213
+ } else if (n >= 1) {
214
+ *d = *s;
215
+ }
216
+ }
217
+ #endif
218
+
194
219
  #endif /* OJ_SIMD_H */
data/ext/oj/sparse.c CHANGED
@@ -399,6 +399,7 @@ static void read_num(ParseInfo pi) {
399
399
  char c;
400
400
 
401
401
  reader_protect(&pi->rd);
402
+ ni.pi = pi;
402
403
  ni.i = 0;
403
404
  ni.num = 0;
404
405
  ni.div = 1;
@@ -415,7 +416,7 @@ static void read_num(ParseInfo pi) {
415
416
  ni.bigdec_load = pi->options.compat_bigdec;
416
417
  } else {
417
418
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
418
- RubyDec == pi->options.bigdec_load);
419
+ RubyDec == pi->options.bigdec_load);
419
420
  ni.bigdec_load = pi->options.bigdec_load;
420
421
  }
421
422
 
@@ -549,6 +550,7 @@ static void read_nan(ParseInfo pi) {
549
550
  struct _numInfo ni;
550
551
  char c;
551
552
 
553
+ ni.pi = pi;
552
554
  ni.str = pi->rd.str;
553
555
  ni.i = 0;
554
556
  ni.num = 0;
@@ -565,7 +567,7 @@ static void read_nan(ParseInfo pi) {
565
567
  ni.bigdec_load = pi->options.compat_bigdec;
566
568
  } else {
567
569
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
568
- RubyDec == pi->options.bigdec_load);
570
+ RubyDec == pi->options.bigdec_load);
569
571
  ni.bigdec_load = pi->options.bigdec_load;
570
572
  }
571
573
 
@@ -745,6 +747,7 @@ void oj_sparse2(ParseInfo pi) {
745
747
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
746
748
  return;
747
749
  }
750
+ ni.pi = pi;
748
751
  ni.str = pi->rd.str;
749
752
  ni.i = 0;
750
753
  ni.num = 0;
@@ -761,7 +764,7 @@ void oj_sparse2(ParseInfo pi) {
761
764
  ni.bigdec_load = pi->options.compat_bigdec;
762
765
  } else {
763
766
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
764
- RubyDec == pi->options.bigdec_load);
767
+ RubyDec == pi->options.bigdec_load);
765
768
  ni.bigdec_load = pi->options.bigdec_load;
766
769
  }
767
770
  add_num_value(pi, &ni);
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/ext/oj/wab.c CHANGED
@@ -19,7 +19,7 @@
19
19
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
20
  #define OJ_INFINITY (1.0 / 0.0)
21
21
 
22
- static char hex_chars[256] = "\
22
+ static char hex_chars[257] = "\
23
23
  ................................\
24
24
  ................xxxxxxxxxx......\
25
25
  .xxxxxx.........................\
data/lib/oj/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Oj
2
2
  # Current version of the module.
3
- VERSION = '3.16.16'
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.16.16
4
+ version: 3.17.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
@@ -158,6 +158,8 @@ files:
158
158
  - ext/oj/resolve.h
159
159
  - ext/oj/rxclass.c
160
160
  - ext/oj/rxclass.h
161
+ - ext/oj/safe.c
162
+ - ext/oj/safe.h
161
163
  - ext/oj/saj.c
162
164
  - ext/oj/saj2.c
163
165
  - ext/oj/saj2.h
@@ -229,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
229
231
  - !ruby/object:Gem::Version
230
232
  version: '0'
231
233
  requirements: []
232
- rubygems_version: 3.6.9
234
+ rubygems_version: 4.0.3
233
235
  specification_version: 4
234
236
  summary: A fast JSON parser and serializer.
235
237
  test_files: []