oj 3.17.4 → 3.17.5

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/sparse.c CHANGED
@@ -290,13 +290,13 @@ static void read_escaped_str(ParseInfo pi) {
290
290
  case NEXT_HASH_NEW:
291
291
  case NEXT_HASH_KEY:
292
292
  if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
293
- parent->klen = buf_len(&buf);
294
- parent->key = malloc(parent->klen + 1);
295
- memcpy((char *)parent->key, buf.head, parent->klen);
296
- *(char *)(parent->key + parent->klen) = '\0';
293
+ parent->klen = buf_len(&buf);
294
+ parent->key = oj_strndup(buf.head, parent->klen);
295
+ parent->kalloc = 1;
297
296
  } else {
298
- parent->key = "";
299
- parent->klen = 0;
297
+ parent->key = "";
298
+ parent->klen = 0;
299
+ parent->kalloc = 0;
300
300
  }
301
301
  parent->k1 = *pi->rd.str;
302
302
  parent->next = NEXT_HASH_COLON;
@@ -906,6 +906,7 @@ CLEANUP:
906
906
  if (0 != pi->circ_array) {
907
907
  oj_circ_array_free(pi->circ_array);
908
908
  }
909
+ reader_cleanup(&pi->rd);
909
910
  stack_cleanup(&pi->stack);
910
911
  // A :match_string option builds a chain of regexps for this call that has to
911
912
  // be freed. Without the option the member aliases the chain owned by the
@@ -78,6 +78,8 @@ void oj_str_writer_init(StrWriter sw, int buf_size) {
78
78
  sw->out.argv = NULL;
79
79
  sw->out.ropts = NULL;
80
80
  sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
81
+ // oj_str_writer_init does not call oj_out_init, so clear this here too.
82
+ sw->out.key_filter_off = false;
81
83
  }
82
84
 
83
85
  void oj_str_writer_push_key(StrWriter sw, const char *key) {
data/ext/oj/usual.c CHANGED
@@ -831,6 +831,7 @@ static VALUE opt_create_id_set(ojParser p, VALUE value) {
831
831
  Usual d = (Usual)p->ctx;
832
832
 
833
833
  if (Qnil == value) {
834
+ OJ_R_FREE(d->create_id);
834
835
  d->create_id = NULL;
835
836
  d->create_id_len = 0;
836
837
  p->funcs[OBJECT_FUN].add_str = add_str_key;
@@ -850,12 +851,15 @@ static VALUE opt_create_id_set(ojParser p, VALUE value) {
850
851
  if (1 << (8 * sizeof(d->create_id_len)) <= len) {
851
852
  rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << (8 * sizeof(d->create_id_len)));
852
853
  }
853
- d->create_id_len = (uint8_t)len;
854
+ char *prev = d->create_id;
855
+
854
856
  d->create_id = str_dup(RSTRING_PTR(value), len);
857
+ d->create_id_len = (uint8_t)len;
855
858
  p->funcs[OBJECT_FUN].add_str = add_str_key_create;
856
859
  p->funcs[TOP_FUN].close_object = close_object_create;
857
860
  p->funcs[ARRAY_FUN].close_object = close_object_create;
858
861
  p->funcs[OBJECT_FUN].close_object = close_object_create;
862
+ OJ_R_FREE(prev);
859
863
  }
860
864
  return opt_create_id(p, value);
861
865
  }
data/ext/oj/util.c CHANGED
@@ -134,3 +134,30 @@ void sec_as_time(int64_t secs, TimeInfo ti) {
134
134
  secs = secs - (int64_t)ti->min * 60LL;
135
135
  ti->sec = (int)secs;
136
136
  }
137
+
138
+ // The inverse of sec_as_time(). The days are counted with the civil calendar
139
+ // algorithm from Howard Hinnant's date library so that no libc call is needed.
140
+ // timegm() is not available on Windows and the mktime() based replacement that
141
+ // was used there returned the wrong value in any timezone east of UTC.
142
+ int64_t time_as_sec(TimeInfo ti) {
143
+ int64_t year = (int64_t)ti->year;
144
+ int64_t mon = (int64_t)ti->mon;
145
+ int64_t era;
146
+ int64_t yoe; // year of the era, [0, 399]
147
+ int64_t doy; // day of the year, [0, 365]
148
+ int64_t doe; // day of the era, [0, 146096]
149
+ int64_t days; // days since 1970-01-01
150
+
151
+ // Start the year on March 1st so that a leap day falls on the last day of
152
+ // the year and the day of the year is a simple expression.
153
+ if (mon <= 2) {
154
+ year--;
155
+ }
156
+ era = (0 <= year ? year : year - 399) / 400;
157
+ yoe = year - era * 400;
158
+ doy = (153 * (mon + (2 < mon ? -3 : 9)) + 2) / 5 + (int64_t)ti->day - 1;
159
+ doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
160
+ days = era * 146097 + doe - 719468;
161
+
162
+ return days * SECS_PER_DAY + (int64_t)ti->hour * 3600LL + (int64_t)ti->min * 60LL + (int64_t)ti->sec;
163
+ }
data/ext/oj/util.h CHANGED
@@ -15,6 +15,7 @@ typedef struct _timeInfo {
15
15
  int year;
16
16
  }* TimeInfo;
17
17
 
18
- extern void sec_as_time(int64_t secs, TimeInfo ti);
18
+ extern void sec_as_time(int64_t secs, TimeInfo ti);
19
+ extern int64_t time_as_sec(TimeInfo ti);
19
20
 
20
21
  #endif /* OJ_UTIL_H */
data/ext/oj/val_stack.h CHANGED
@@ -35,8 +35,8 @@ typedef struct _val {
35
35
  const char *classname;
36
36
  VALUE clas;
37
37
  OddArgs odd_args;
38
- uint16_t klen;
39
- uint16_t clen;
38
+ size_t klen;
39
+ size_t clen;
40
40
  char next; // ValNext
41
41
  char k1; // first original character in the key
42
42
  char kalloc;
@@ -62,6 +62,16 @@ inline static int stack_empty(ValStack stack) {
62
62
  }
63
63
 
64
64
  inline static void stack_cleanup(ValStack stack) {
65
+ Val v;
66
+
67
+ // end_hash() frees the args of a completed odd class. Anything still here
68
+ // belongs to a parse that was abandoned part way through.
69
+ for (v = stack->head; v < stack->tail; v++) {
70
+ if (NULL != v->odd_args) {
71
+ oj_odd_free(v->odd_args);
72
+ v->odd_args = NULL;
73
+ }
74
+ }
65
75
  if (stack->base != stack->head) {
66
76
  OJ_R_FREE(stack->head);
67
77
  stack->head = NULL;
@@ -70,9 +80,11 @@ inline static void stack_cleanup(ValStack stack) {
70
80
 
71
81
  inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
72
82
  if (stack->end <= stack->tail) {
73
- size_t len = stack->end - stack->head;
74
- size_t toff = stack->tail - stack->head;
75
- Val head = stack->head;
83
+ size_t len = stack->end - stack->head;
84
+ size_t toff = stack->tail - stack->head;
85
+ Val head = stack->head;
86
+ const char *old = (const char *)stack->head;
87
+ size_t i;
76
88
 
77
89
  // A realloc can trigger a GC so make sure it happens outside the lock
78
90
  // but lock before changing pointers.
@@ -82,6 +94,13 @@ inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
82
94
  } else {
83
95
  OJ_R_REALLOC_N(head, struct _val, len + STACK_INC);
84
96
  }
97
+ // A key short enough to be kept in the Val itself points into the
98
+ // block that just moved.
99
+ for (i = 0; i < toff; i++) {
100
+ if (old <= head[i].key && head[i].key < old + sizeof(struct _val) * len) {
101
+ head[i].key = head[i].karray;
102
+ }
103
+ }
85
104
  #ifdef HAVE_PTHREAD_MUTEX_INIT
86
105
  pthread_mutex_lock(&stack->mutex);
87
106
  #else
data/ext/oj/wab.c CHANGED
@@ -375,44 +375,41 @@ static const char *read_num(const char *s, int len, int *vp) {
375
375
  }
376
376
 
377
377
  static VALUE time_parse(const char *s, int len) {
378
- struct tm tm;
379
- bool neg = false;
380
- long nsecs = 0;
381
- int i;
382
- time_t secs;
378
+ struct _timeInfo ti;
379
+ bool neg = false;
380
+ long nsecs = 0;
381
+ int i;
383
382
 
384
- memset(&tm, 0, sizeof(tm));
383
+ memset(&ti, 0, sizeof(ti));
385
384
  if ('-' == *s) {
386
385
  s++;
387
386
  neg = true;
388
387
  }
389
- if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
388
+ if (NULL == (s = read_num(s, 4, &ti.year))) {
390
389
  return Qnil;
391
390
  }
392
391
  if (neg) {
393
- tm.tm_year = -tm.tm_year;
394
- neg = false;
392
+ ti.year = -ti.year;
393
+ neg = false;
395
394
  }
396
- tm.tm_year -= 1900;
397
395
  s++;
398
- if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
396
+ if (NULL == (s = read_num(s, 2, &ti.mon))) {
399
397
  return Qnil;
400
398
  }
401
- tm.tm_mon--;
402
399
  s++;
403
- if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
400
+ if (NULL == (s = read_num(s, 2, &ti.day))) {
404
401
  return Qnil;
405
402
  }
406
403
  s++;
407
- if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
404
+ if (NULL == (s = read_num(s, 2, &ti.hour))) {
408
405
  return Qnil;
409
406
  }
410
407
  s++;
411
- if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
408
+ if (NULL == (s = read_num(s, 2, &ti.min))) {
412
409
  return Qnil;
413
410
  }
414
411
  s++;
415
- if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
412
+ if (NULL == (s = read_num(s, 2, &ti.sec))) {
416
413
  return Qnil;
417
414
  }
418
415
  s++;
@@ -424,16 +421,7 @@ static VALUE time_parse(const char *s, int len) {
424
421
  return Qnil;
425
422
  }
426
423
  }
427
- #if IS_WINDOWS
428
- secs = (time_t)mktime(&tm);
429
- memset(&tm, 0, sizeof(tm));
430
- tm.tm_year = 70;
431
- tm.tm_mday = 1;
432
- secs -= (time_t)mktime(&tm);
433
- #else
434
- secs = (time_t)timegm(&tm);
435
- #endif
436
- return rb_funcall(rb_time_nano_new(secs, nsecs), oj_utc_id, 0);
424
+ return rb_funcall(rb_time_nano_new((time_t)time_as_sec(&ti), nsecs), oj_utc_id, 0);
437
425
  }
438
426
 
439
427
  static VALUE protect_uri(VALUE rstr) {
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.4'
3
+ VERSION = '3.17.5'
4
4
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Ruby**
4
4
 
5
- Oj is compatible with Ruby 2.4+ and RBX.
5
+ Oj is compatible with Ruby 2.7+ and RBX.
6
6
  Support for JRuby has been removed as JRuby no longer supports C extensions and
7
7
  there are bugs in the older versions that are not being fixed.
8
8
 
data/pages/Custom.md CHANGED
@@ -8,9 +8,8 @@ for object dumping and loading. The `:compat` mode mimic the json gem
8
8
  including methods called for encoding and inconsistencies between
9
9
  `JSON.dump()`, `JSON.generate()`, and `JSON()`.
10
10
 
11
- The `:custom` mode is the default mode. It can be configured either by passing
12
- options to the `Oj.dump()` and `Oj.load()` methods or by modifying the default
13
- options.
11
+ The `:custom` mode can be configured either by passing options to the
12
+ `Oj.dump()` and `Oj.load()` methods or by modifying the default options.
14
13
 
15
14
  The ability to create objects from JSON object elements is supported and
16
15
  considers the `:create_additions` option. Special treatment is given to the
@@ -10,11 +10,13 @@ To enable Oj trace feature, it uses `--enable-trace-log` option when installing
10
10
  Then, the trace logs will be displayed when `:trace` option is set to `true`.
11
11
 
12
12
 
13
- ### Enable SIMD instructions
13
+ ### SIMD instructions
14
14
 
15
- ```
16
- $ gem install oj -- --with-sse42
17
- ```
15
+ SIMD optimizations are enabled automatically, so no install option is
16
+ required. At runtime Oj detects the CPU features that are available and
17
+ selects the best implementation: SSE4.2 or SSE2 on x86 / x86_64, NEON on ARM,
18
+ and a scalar fallback when none is available.
18
19
 
19
- To enable the use of SIMD instructions in Oj, it uses the `--with-sse42` option when installing the gem.
20
- This will enable the use of the SSE4.2 instructions in the internal.
20
+ Earlier versions required a `--with-sse42` option at install time to turn on
21
+ SSE4.2. That option has been removed (#982); SSE4.2 is now selected
22
+ automatically when the CPU supports it.
data/pages/Modes.md CHANGED
@@ -121,7 +121,7 @@ information.
121
121
  | :object_nl | String | | | x | x | | x | |
122
122
  | :omit_nil | Boolean | x | x | x | x | x | x | |
123
123
  | :quirks_mode | Boolean | | | 6 | | | x | |
124
- | :safe | String | | | x | | | | |
124
+ | :safe | Boolean | | | x | | | | |
125
125
  | :second_precision | Fixnum | | | | | x | x | |
126
126
  | :space | String | | | x | x | | x | |
127
127
  | :space_before | String | | | x | x | | x | |
data/pages/Options.md CHANGED
@@ -213,8 +213,7 @@ for json gem compatibility.
213
213
 
214
214
  Primary behavior for loading and dumping. The :mode option controls which
215
215
  other options are in effect. For more details see the {file:Modes.md} page. By
216
- default Oj uses the :custom mode which is provides the highest degree of
217
- customization.
216
+ default Oj uses the :object mode.
218
217
 
219
218
  ### :nan [Symbol]
220
219
 
@@ -249,6 +248,10 @@ integer gives better performance.
249
248
 
250
249
  If true, Hash and Object attributes with nil values are omitted.
251
250
 
251
+ ### :omit_null_byte [Boolean]
252
+
253
+ If true, null bytes in strings will be omitted when dumping.
254
+
252
255
  ### :quirks_mode [Boolean]
253
256
 
254
257
  Allow single JSON values instead of documents, default is true (allow). This
@@ -265,10 +268,6 @@ to true.
265
268
 
266
269
  The number of digits after the decimal when dumping the seconds of time.
267
270
 
268
- ### :skip_null_byte [Boolean]
269
-
270
- If true, null bytes in strings will be omitted when dumping.
271
-
272
271
  ### :space
273
272
 
274
273
  String inserted after the ':' character when dumping a JSON object. The
data/pages/Parser.md CHANGED
@@ -280,7 +280,7 @@ Oj::Parser.usual 0.452 110544.876
280
280
  JSON::Ext 1.009 49555.094
281
281
  ```
282
282
 
283
- The `Oj::Parser.new(:saj)` is **1.55** times faster than `Oj.load` and
283
+ The `Oj::Parser.new(:usual)` is **1.55** times faster than `Oj.load` and
284
284
  **2.23** times faster than the JSON gem.
285
285
 
286
286
  ### Object
@@ -298,7 +298,7 @@ Oj::Parser.usual 0.071 703502.033
298
298
  JSON::Ext 0.401 124638.859
299
299
  ```
300
300
 
301
- The `Oj::Parser.new(:saj)` is **3.17** times faster than
301
+ The `Oj::Parser.new(:usual)` is **3.17** times faster than
302
302
  `Oj.compat_load` and **5.64** times faster than the JSON gem.
303
303
 
304
304
  ## Summary
data/pages/Rails.md CHANGED
@@ -89,6 +89,8 @@ The classes that can be put in optimized mode and are optimized when
89
89
  * any class inheriting from ActiveRecord::Base
90
90
  * any other class where all attributes should be dumped
91
91
 
92
+ Both `Oj::Rails` and each `Oj::Rails::Encoder` have `optimize()`, `deoptimize()`, and `optimized?()` methods. The module level methods change the setting for the whole process. An encoder follows those process wide settings until `optimize()` or `deoptimize()` is called on the encoder itself. From then on the encoder keeps a set of its own and later module level changes do not reach it.
93
+
92
94
  The ActiveSupport decoder is the `JSON.parse()` method. Calling the
93
95
  `Oj::Rails.set_decoder()` method replaces that method with the Oj equivalent.
94
96
 
data/pages/Security.md CHANGED
@@ -11,10 +11,24 @@ auto defined is used with an untrusted source. The `Oj.safe_load()` method
11
11
  sets and uses the most strict and safest options. It should be used by
12
12
  developers who find it difficult to understand the options available in Oj.
13
13
 
14
- The options in Oj are designed to provide flexibility to the developer. This
15
- flexibility allows Objects to be serialized and deserialized. No methods are
16
- ever called on these created Objects but that does not stop the developer from
17
- calling methods on them. As in any system, check your inputs before working with
18
- them. Taking an arbitrary `String` from a user and evaluating it is never a good
19
- idea from an unsecure source. The same is true for `Object` attributes as they
20
- are not more than `String`s. Always check inputs from untrusted sources.
14
+ The options in Oj are designed to provide flexibility to the developer. This flexibility allows Objects to be serialized and deserialized. An Object is deserialized by allocating it without calling its initializer and then setting its instance variables. A few methods are called on what that builds: `exception` and `set_backtrace` on an `Exception`, and `replace` on a subclass of `Hash`, `Array` or `String` for a `self` key. As in any system, check your inputs before working with them. Taking an arbitrary `String` from a user and evaluating it is never a good idea from an unsecure source. The same is true for `Object` attributes as they are not more than `String`s. Always check inputs from untrusted sources.
15
+
16
+ ## The mode a document is loaded in
17
+
18
+ `Oj.load()` uses the `:object` mode unless the mode is changed. That mode takes the class of an Object from the document, so the document decides which of the classes already loaded in the process is allocated and what its instance variables are. Classes are looked up and not created unless `:auto_define` is turned on.
19
+
20
+ For a document from an untrusted source, ask for a mode that does not do that:
21
+
22
+ ```ruby
23
+ Oj.load(json, mode: :strict)
24
+ Oj.strict_load(json)
25
+ Oj.safe_load(json)
26
+ ```
27
+
28
+ or set it for the process:
29
+
30
+ ```ruby
31
+ Oj.default_options = {mode: :strict}
32
+ ```
33
+
34
+ `Oj.object_load()` is the explicit form of the current default and stays in `:object` mode whatever the default is set to.
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.4
4
+ version: 3.17.5
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.3
234
+ rubygems_version: 4.0.17
235
235
  specification_version: 4
236
236
  summary: A fast JSON parser and serializer.
237
237
  test_files: []