oj 2.1.7 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

@@ -72,7 +72,7 @@ hash_key(ParseInfo pi, const char *key, size_t klen, char k1) {
72
72
 
73
73
  static VALUE
74
74
  str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
75
- VALUE rstr = Qnil;
75
+ volatile VALUE rstr = Qnil;
76
76
 
77
77
  if (':' == *orig && 0 < len) {
78
78
  rstr = rb_str_new(str + 1, len - 1);
@@ -183,11 +183,11 @@ static int
183
183
  hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, VALUE value) {
184
184
  if (2 == klen && 'u' == key[1] && T_ARRAY == rb_type(value)) {
185
185
  #if HAS_RSTRUCT
186
- long len = RARRAY_LEN(value);
187
- VALUE *a = RARRAY_PTR(value);
188
- VALUE sc;
189
- VALUE s;
190
- VALUE *sv;
186
+ long len = RARRAY_LEN(value);
187
+ VALUE *a = RARRAY_PTR(value);
188
+ VALUE sc;
189
+ volatile VALUE s;
190
+ VALUE *sv;
191
191
 
192
192
  if (0 == len) {
193
193
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
@@ -231,11 +231,11 @@ hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, VALUE value) {
231
231
 
232
232
  static void
233
233
  copy_ivars(VALUE target, VALUE src) {
234
- VALUE vars = rb_funcall(src, oj_instance_variables_id, 0);
235
- VALUE *np = RARRAY_PTR(vars);
236
- ID vid;
237
- int i, cnt = (int)RARRAY_LEN(vars);
238
- const char *attr;
234
+ volatile VALUE vars = rb_funcall(src, oj_instance_variables_id, 0);
235
+ VALUE *np = RARRAY_PTR(vars);
236
+ ID vid;
237
+ int i, cnt = (int)RARRAY_LEN(vars);
238
+ const char *attr;
239
239
 
240
240
  for (i = cnt; 0 < i; i--, np++) {
241
241
  vid = rb_to_id(*np);
@@ -80,6 +80,7 @@ ID oj_write_id;
80
80
 
81
81
  VALUE oj_bag_class;
82
82
  VALUE oj_bigdecimal_class;
83
+ VALUE oj_cstack_class;
83
84
  VALUE oj_date_class;
84
85
  VALUE oj_datetime_class;
85
86
  VALUE oj_parse_error_class;
@@ -89,6 +90,7 @@ VALUE oj_time_class;
89
90
 
90
91
  VALUE oj_slash_string;
91
92
 
93
+ static VALUE ascii_sym;
92
94
  static VALUE ascii_only_sym;
93
95
  static VALUE auto_define_sym;
94
96
  static VALUE bigdecimal_as_decimal_sym;
@@ -97,10 +99,13 @@ static VALUE circular_sym;
97
99
  static VALUE class_cache_sym;
98
100
  static VALUE compat_sym;
99
101
  static VALUE create_id_sym;
102
+ static VALUE escape_mode_sym;
100
103
  static VALUE indent_sym;
104
+ static VALUE json_sym;
101
105
  static VALUE mode_sym;
102
106
  static VALUE null_sym;
103
107
  static VALUE object_sym;
108
+ static VALUE xss_safe_sym;
104
109
  static VALUE ruby_sym;
105
110
  static VALUE sec_prec_sym;
106
111
  static VALUE strict_sym;
@@ -134,7 +139,7 @@ struct _Options oj_default_options = {
134
139
  No, // circular
135
140
  No, // auto_define
136
141
  No, // sym_key
137
- No, // ascii_only
142
+ JSONEsc, // escape_mode
138
143
  ObjectMode, // mode
139
144
  Yes, // class_cache
140
145
  UnixTime, // time_format
@@ -155,6 +160,7 @@ static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
155
160
  * - circular: [true|false|nil] support circular references while dumping
156
161
  * - auto_define: [true|false|nil] automatically define classes if they do not exist
157
162
  * - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
163
+ * - escape_mode: [:json|:xss_safe|:ascii|nil] use symbols instead of strings for hash keys
158
164
  * - class_cache: [true|false|nil] cache classes for faster parsing (if dynamically modifying classes or reloading classes then don't use this)
159
165
  * - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
160
166
  * - time_format: [:unix|:xmlschema|:ruby] time format when dumping in :compat mode
@@ -173,7 +179,6 @@ get_def_opts(VALUE self) {
173
179
  rb_hash_aset(opts, circular_sym, (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
174
180
  rb_hash_aset(opts, class_cache_sym, (Yes == oj_default_options.class_cache) ? Qtrue : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
175
181
  rb_hash_aset(opts, auto_define_sym, (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
176
- rb_hash_aset(opts, ascii_only_sym, (Yes == oj_default_options.ascii_only) ? Qtrue : ((No == oj_default_options.ascii_only) ? Qfalse : Qnil));
177
182
  rb_hash_aset(opts, symbol_keys_sym, (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
178
183
  rb_hash_aset(opts, bigdecimal_as_decimal_sym, (Yes == oj_default_options.bigdec_as_num) ? Qtrue : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
179
184
  rb_hash_aset(opts, bigdecimal_load_sym, (Yes == oj_default_options.bigdec_load) ? Qtrue : ((No == oj_default_options.bigdec_load) ? Qfalse : Qnil));
@@ -184,6 +189,12 @@ get_def_opts(VALUE self) {
184
189
  case ObjectMode:
185
190
  default: rb_hash_aset(opts, mode_sym, object_sym); break;
186
191
  }
192
+ switch (oj_default_options.escape_mode) {
193
+ case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
194
+ case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
195
+ case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
196
+ default: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
197
+ }
187
198
  switch (oj_default_options.time_format) {
188
199
  case XmlTime: rb_hash_aset(opts, time_format_sym, xmlschema_sym); break;
189
200
  case RubyTime: rb_hash_aset(opts, time_format_sym, ruby_sym); break;
@@ -204,7 +215,9 @@ get_def_opts(VALUE self) {
204
215
  * @param [true|false|nil] :auto_define automatically define classes if they do not exist
205
216
  * @param [true|false|nil] :symbol_keys convert hash keys to symbols
206
217
  * @param [true|false|nil] :class_cache cache classes for faster parsing
207
- * @param [true|false|nil] :ascii_only encode all high-bit characters as escaped sequences if true
218
+ * @param [:json|:xss_safe|:ascii|nil] :escape mode encodes all high-bit characters as
219
+ * escaped sequences if :ascii, :json is standand UTF-8 JSON encoding,
220
+ * and :xss_safe escapes &, <, and >, and some others.
208
221
  * @param [true|false|nil] :bigdecimal_as_decimal dump BigDecimal as a decimal number or as a String
209
222
  * @param [true|false|nil] :bigdecimal_load load decimals as a BigDecimal instead of as a Float
210
223
  * @param [:object|:strict|:compat|:null] load and dump mode to use for JSON
@@ -230,7 +243,6 @@ set_def_opts(VALUE self, VALUE opts) {
230
243
  { auto_define_sym, &oj_default_options.auto_define },
231
244
  { symbol_keys_sym, &oj_default_options.sym_key },
232
245
  { class_cache_sym, &oj_default_options.class_cache },
233
- { ascii_only_sym, &oj_default_options.ascii_only },
234
246
  { bigdecimal_as_decimal_sym, &oj_default_options.bigdec_as_num },
235
247
  { bigdecimal_load_sym, &oj_default_options.bigdec_load },
236
248
  { Qnil, 0 }
@@ -286,6 +298,19 @@ set_def_opts(VALUE self, VALUE opts) {
286
298
  rb_raise(rb_eArgError, ":time_format must be :unix, :xmlschema, or :ruby.");
287
299
  }
288
300
 
301
+ v = rb_hash_lookup(opts, escape_mode_sym);
302
+ if (Qnil == v) {
303
+ // ignore
304
+ } else if (json_sym == v) {
305
+ oj_default_options.escape_mode = JSONEsc;
306
+ } else if (xss_safe_sym == v) {
307
+ oj_default_options.escape_mode = XSSEsc;
308
+ } else if (ascii_sym == v) {
309
+ oj_default_options.escape_mode = ASCIIEsc;
310
+ } else {
311
+ rb_raise(rb_eArgError, ":encoding must be :json, :rails, or :ascii.");
312
+ }
313
+
289
314
  if (Qtrue == rb_funcall(opts, rb_intern("has_key?"), 1, create_id_sym)) {
290
315
  if (0 != oj_default_options.create_id) {
291
316
  if (json_class != oj_default_options.create_id) {
@@ -318,6 +343,13 @@ set_def_opts(VALUE self, VALUE opts) {
318
343
  }
319
344
  }
320
345
  }
346
+ // This is here only for backwards compatibility with the original Oj.
347
+ v = rb_hash_lookup(opts, ascii_only_sym);
348
+ if (Qtrue == v) {
349
+ oj_default_options.escape_mode = ASCIIEsc;
350
+ } else if (Qfalse == v) {
351
+ oj_default_options.escape_mode = JSONEsc;
352
+ }
321
353
  return Qnil;
322
354
  }
323
355
 
@@ -328,7 +360,6 @@ oj_parse_options(VALUE ropts, Options copts) {
328
360
  { auto_define_sym, &copts->auto_define },
329
361
  { symbol_keys_sym, &copts->sym_key },
330
362
  { class_cache_sym, &copts->class_cache },
331
- { ascii_only_sym, &copts->ascii_only },
332
363
  { bigdecimal_as_decimal_sym, &copts->bigdec_as_num },
333
364
  { bigdecimal_load_sym, &copts->bigdec_load },
334
365
  { Qnil, 0 }
@@ -382,6 +413,19 @@ oj_parse_options(VALUE ropts, Options copts) {
382
413
  rb_raise(rb_eArgError, ":time_format must be :unix, :xmlschema, or :ruby.");
383
414
  }
384
415
  }
416
+
417
+ if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) {
418
+ if (json_sym == v) {
419
+ copts->escape_mode = JSONEsc;
420
+ } else if (xss_safe_sym == v) {
421
+ copts->escape_mode = XSSEsc;
422
+ } else if (ascii_sym == v) {
423
+ copts->escape_mode = ASCIIEsc;
424
+ } else {
425
+ rb_raise(rb_eArgError, ":encoding must be :json, :rails, or :ascii.");
426
+ }
427
+ }
428
+
385
429
  if (Qtrue == rb_funcall(ropts, rb_intern("has_key?"), 1, create_id_sym)) {
386
430
  v = rb_hash_lookup(ropts, create_id_sym);
387
431
  if (Qnil == v) {
@@ -415,6 +459,13 @@ oj_parse_options(VALUE ropts, Options copts) {
415
459
  }
416
460
  }
417
461
  }
462
+ // This is here only for backwards compatibility with the original Oj.
463
+ v = rb_hash_lookup(ropts, ascii_only_sym);
464
+ if (Qtrue == v) {
465
+ copts->escape_mode = ASCIIEsc;
466
+ } else if (Qfalse == v) {
467
+ copts->escape_mode = JSONEsc;
468
+ }
418
469
  }
419
470
  }
420
471
 
@@ -1009,7 +1060,7 @@ mimic_create_id(VALUE self, VALUE id) {
1009
1060
  * will be replaced with Oj methods.
1010
1061
  *
1011
1062
  * Note that this also sets the default options of :mode to :compat and
1012
- * :ascii_only to true.
1063
+ * :encoding to :ascii.
1013
1064
  */
1014
1065
  static VALUE
1015
1066
  define_mimic_json(int argc, VALUE *argv, VALUE self) {
@@ -1079,7 +1130,7 @@ define_mimic_json(int argc, VALUE *argv, VALUE self) {
1079
1130
  symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
1080
1131
 
1081
1132
  oj_default_options.mode = CompatMode;
1082
- oj_default_options.ascii_only = Yes;
1133
+ oj_default_options.escape_mode = ASCIIEsc;
1083
1134
 
1084
1135
  return mimic;
1085
1136
  }
@@ -1114,6 +1165,8 @@ iconv_rescue(VALUE x) {
1114
1165
  void Init_oj() {
1115
1166
  Oj = rb_define_module("Oj");
1116
1167
 
1168
+ oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
1169
+
1117
1170
  rb_require("time");
1118
1171
  rb_require("date");
1119
1172
  rb_require("bigdecimal");
@@ -1185,6 +1238,7 @@ void Init_oj() {
1185
1238
  oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
1186
1239
  oj_time_class = rb_const_get(rb_cObject, rb_intern("Time"));
1187
1240
 
1241
+ ascii_sym = ID2SYM(rb_intern("ascii")); rb_gc_register_address(&ascii_sym);
1188
1242
  ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&ascii_only_sym);
1189
1243
  auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
1190
1244
  bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));rb_gc_register_address(&bigdecimal_as_decimal_sym);
@@ -1193,10 +1247,13 @@ void Init_oj() {
1193
1247
  class_cache_sym = ID2SYM(rb_intern("class_cache")); rb_gc_register_address(&class_cache_sym);
1194
1248
  compat_sym = ID2SYM(rb_intern("compat")); rb_gc_register_address(&compat_sym);
1195
1249
  create_id_sym = ID2SYM(rb_intern("create_id")); rb_gc_register_address(&create_id_sym);
1250
+ escape_mode_sym = ID2SYM(rb_intern("escape_mode")); rb_gc_register_address(&escape_mode_sym);
1196
1251
  indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&indent_sym);
1252
+ json_sym = ID2SYM(rb_intern("json")); rb_gc_register_address(&json_sym);
1197
1253
  mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
1198
1254
  null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym);
1199
1255
  object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
1256
+ xss_safe_sym = ID2SYM(rb_intern("xss_safe")); rb_gc_register_address(&xss_safe_sym);
1200
1257
  ruby_sym = ID2SYM(rb_intern("ruby")); rb_gc_register_address(&ruby_sym);
1201
1258
  sec_prec_sym = ID2SYM(rb_intern("second_precision"));rb_gc_register_address(&sec_prec_sym);
1202
1259
  strict_sym = ID2SYM(rb_intern("strict")); rb_gc_register_address(&strict_sym);
@@ -85,6 +85,12 @@ typedef enum {
85
85
  RubyTime = 'r'
86
86
  } TimeFormat;
87
87
 
88
+ typedef enum {
89
+ JSONEsc = 'j',
90
+ XSSEsc = 'x',
91
+ ASCIIEsc = 'a'
92
+ } Encoding;
93
+
88
94
  typedef struct _DumpOpts {
89
95
  const char *indent;
90
96
  const char *before_sep;
@@ -103,7 +109,7 @@ typedef struct _Options {
103
109
  char circular; // YesNo
104
110
  char auto_define; // YesNo
105
111
  char sym_key; // YesNo
106
- char ascii_only; // YesNo
112
+ char escape_mode; // Escape_Mode
107
113
  char mode; // Mode
108
114
  char class_cache; // YesNo
109
115
  char time_format; // TimeFormat
@@ -181,6 +187,7 @@ extern VALUE oj_utf8_encoding;
181
187
 
182
188
  extern VALUE oj_bag_class;
183
189
  extern VALUE oj_bigdecimal_class;
190
+ extern VALUE oj_cstack_class;
184
191
  extern VALUE oj_date_class;
185
192
  extern VALUE oj_datetime_class;
186
193
  extern VALUE oj_doc_class;
@@ -499,9 +499,8 @@ read_num(ParseInfo pi) {
499
499
 
500
500
  static void
501
501
  array_start(ParseInfo pi) {
502
- VALUE v = Qnil;
502
+ VALUE v = pi->start_array(pi);
503
503
 
504
- v = pi->start_array(pi);
505
504
  stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
506
505
  }
507
506
 
@@ -521,9 +520,8 @@ array_end(ParseInfo pi) {
521
520
 
522
521
  static void
523
522
  hash_start(ParseInfo pi) {
524
- VALUE v = Qnil;
523
+ VALUE v = pi->start_hash(pi);
525
524
 
526
- v = pi->start_hash(pi);
527
525
  stack_push(&pi->stack, v, NEXT_HASH_NEW);
528
526
  }
529
527
 
@@ -571,9 +569,11 @@ colon(ParseInfo pi) {
571
569
 
572
570
  void
573
571
  oj_parse2(ParseInfo pi) {
572
+ volatile VALUE rstack = Qnil;
573
+
574
574
  pi->cur = pi->json;
575
575
  err_init(&pi->err);
576
- stack_init(&pi->stack);
576
+ rstack = oj_stack_init(&pi->stack);
577
577
  while (1) {
578
578
  next_non_white(pi);
579
579
  switch (*pi->cur++) {
@@ -656,7 +656,7 @@ oj_num_as_value(NumInfo ni) {
656
656
  rnum = rb_float_new(OJ_INFINITY);
657
657
  }
658
658
  } else if (ni->nan) {
659
- rnum = rb_float_new(NAN);
659
+ rnum = rb_float_new(0.0/0.0);
660
660
  } else if (1 == ni->div && 0 == ni->exp) { // fixnum
661
661
  if (ni->big) {
662
662
  if (256 > ni->len) {
@@ -719,11 +719,11 @@ protect_parse(VALUE pip) {
719
719
 
720
720
  VALUE
721
721
  oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
722
- char *buf = 0;
723
- VALUE input;
724
- VALUE result = Qnil;
725
- int line = 0;
726
- int free_json = 0;
722
+ char *buf = 0;
723
+ VALUE input;
724
+ volatile VALUE result = Qnil;
725
+ int line = 0;
726
+ int free_json = 0;
727
727
 
728
728
  if (argc < 1) {
729
729
  rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
@@ -784,15 +784,8 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
784
784
  // GC can run at any time. When it runs any Object created by C will be
785
785
  // freed. This usually only happens with large files but it does happen and
786
786
  // it happens more frequently on Ruby 1.8.7.
787
- #if HAS_GC_GUARD
788
- rb_gc_disable();
789
- #endif
790
787
  rb_protect(protect_parse, (VALUE)pi, &line);
791
788
  result = stack_head_val(&pi->stack);
792
- #if HAS_GC_GUARD
793
- RB_GC_GUARD(result);
794
- rb_gc_enable();
795
- #endif
796
789
  // proceed with cleanup
797
790
  if (0 != pi->circ_array) {
798
791
  oj_circ_array_free(pi->circ_array);
@@ -44,12 +44,6 @@
44
44
  #include "oj.h"
45
45
  #include "encode.h"
46
46
 
47
- typedef struct _CX {
48
- VALUE *cur;
49
- VALUE *end;
50
- VALUE stack[1024];
51
- } *CX;
52
-
53
47
  typedef struct _ParseInfo {
54
48
  char *str; /* buffer being read from */
55
49
  char *s; /* current position in buffer */
@@ -145,7 +139,7 @@ next_white(ParseInfo pi) {
145
139
 
146
140
  inline static void
147
141
  call_add_value(VALUE handler, VALUE value, const char *key) {
148
- VALUE k;
142
+ volatile VALUE k;
149
143
 
150
144
  if (0 == key) {
151
145
  k = Qnil;
@@ -158,7 +152,7 @@ call_add_value(VALUE handler, VALUE value, const char *key) {
158
152
 
159
153
  inline static void
160
154
  call_no_value(VALUE handler, ID method, const char *key) {
161
- VALUE k;
155
+ volatile VALUE k;
162
156
 
163
157
  if (0 == key) {
164
158
  k = Qnil;
@@ -668,7 +662,7 @@ respond_to(VALUE obj, ID method) {
668
662
 
669
663
  static void
670
664
  sajkey_parse(VALUE handler, char *json) {
671
- VALUE obj = Qnil;
665
+ volatile VALUE obj = Qnil;
672
666
  struct _ParseInfo pi;
673
667
 
674
668
  if (0 == json) {
@@ -737,14 +731,14 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
737
731
  json = ALLOC_N(char, len);
738
732
  strcpy(json, StringValuePtr(input));
739
733
  } else {
740
- VALUE clas = rb_obj_class(input);
741
- VALUE s;
734
+ VALUE clas = rb_obj_class(input);
735
+ volatile VALUE s;
742
736
 
743
737
  if (oj_stringio_class == clas) {
744
738
  s = rb_funcall2(input, oj_string_id, 0, 0);
745
739
  len = RSTRING_LEN(s) + 1;
746
740
  json = ALLOC_N(char, len);
747
- strcpy(json, StringValuePtr(s));
741
+ strcpy(json, rb_string_value_cstr((VALUE*)&s));
748
742
  #ifndef JRUBY_RUBY
749
743
  #if !IS_WINDOWS
750
744
  // JRuby gets confused with what is the real fileno.
@@ -765,7 +759,7 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
765
759
  s = rb_funcall2(input, oj_read_id, 0, 0);
766
760
  len = RSTRING_LEN(s) + 1;
767
761
  json = ALLOC_N(char, len);
768
- strcpy(json, StringValuePtr(s));
762
+ strcpy(json, rb_string_value_cstr((VALUE*)&s));
769
763
  } else {
770
764
  rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
771
765
  }
@@ -107,7 +107,7 @@ add_value(ParseInfo pi, VALUE val) {
107
107
 
108
108
  static void
109
109
  add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
110
- VALUE rstr = rb_str_new(str, len);
110
+ volatile VALUE rstr = rb_str_new(str, len);
111
111
 
112
112
  rstr = oj_encode(rstr);
113
113
  rb_funcall((VALUE)pi->cbc, oj_add_value_id, 1, rstr);
@@ -140,7 +140,7 @@ end_array(ParseInfo pi) {
140
140
 
141
141
  static VALUE
142
142
  hash_key(ParseInfo pi, const char *key, size_t klen) {
143
- VALUE rkey = rb_str_new(key, klen);
143
+ volatile VALUE rkey = rb_str_new(key, klen);
144
144
 
145
145
  rkey = oj_encode(rkey);
146
146
  if (Yes == pi->options.sym_key) {
@@ -151,7 +151,7 @@ hash_key(ParseInfo pi, const char *key, size_t klen) {
151
151
 
152
152
  static void
153
153
  hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
154
- VALUE rstr = rb_str_new(str, len);
154
+ volatile VALUE rstr = rb_str_new(str, len);
155
155
 
156
156
  rstr = oj_encode(rstr);
157
157
  rb_funcall((VALUE)pi->cbc, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, hash_key(pi, key, klen), rstr);
@@ -169,7 +169,7 @@ hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
169
169
 
170
170
  static void
171
171
  array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
172
- VALUE rstr = rb_str_new(str, len);
172
+ volatile VALUE rstr = rb_str_new(str, len);
173
173
 
174
174
  rstr = oj_encode(rstr);
175
175
  rb_funcall((VALUE)pi->cbc, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr);