oj 3.17.6 → 3.17.8

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/parse.c CHANGED
@@ -390,6 +390,32 @@ void oj_scanner_init(void) {
390
390
  }
391
391
  }
392
392
 
393
+ // JSON does not allow an unescaped control character (below 0x20) in a
394
+ // string. Like a trailing decimal point, that is only rejected in strict mode
395
+ // and when mimicking the JSON gem.
396
+ static inline bool reject_control_chars(ParseInfo pi) {
397
+ return StrictMode == pi->options.mode || CompatMode == pi->options.mode;
398
+ }
399
+
400
+ static const char *find_control_char(const char *s, const char *end) {
401
+ // Eight bytes at a time first: a byte below 0x20 sets its high bit in
402
+ // (w - 0x20...) & ~w.
403
+ for (; s + sizeof(uint64_t) <= end; s += sizeof(uint64_t)) {
404
+ uint64_t w;
405
+
406
+ memcpy(&w, s, sizeof(w));
407
+ if (0 != ((w - 0x2020202020202020ULL) & ~w & 0x8080808080808080ULL)) {
408
+ break;
409
+ }
410
+ }
411
+ for (; s < end; s++) {
412
+ if ((unsigned char)*s < 0x20) {
413
+ return s;
414
+ }
415
+ }
416
+ return NULL;
417
+ }
418
+
393
419
  // entered at /
394
420
  static void read_escaped_str(ParseInfo pi, const char *start) {
395
421
  struct _buf buf;
@@ -409,6 +435,16 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
409
435
  buf_cleanup(&buf);
410
436
  return;
411
437
  }
438
+ if (reject_control_chars(pi)) {
439
+ const char *ctrl = find_control_char(s, scanned);
440
+
441
+ if (NULL != ctrl) {
442
+ pi->cur = ctrl;
443
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid control character in string");
444
+ buf_cleanup(&buf);
445
+ return;
446
+ }
447
+ }
412
448
  buf_append_string(&buf, s, (size_t)(scanned - s));
413
449
  s = scanned;
414
450
 
@@ -543,6 +579,15 @@ static void read_str(ParseInfo pi) {
543
579
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
544
580
  return;
545
581
  }
582
+ if (reject_control_chars(pi)) {
583
+ const char *ctrl = find_control_char(str, pi->cur);
584
+
585
+ if (NULL != ctrl) {
586
+ pi->cur = ctrl;
587
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid control character in string");
588
+ return;
589
+ }
590
+ }
546
591
  if ('\\' == *pi->cur) {
547
592
  read_escaped_str(pi, str);
548
593
  return;
@@ -1205,17 +1250,20 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1205
1250
  }
1206
1251
  } else {
1207
1252
  VALUE clas = rb_obj_class(input);
1208
- VALUE s;
1209
1253
 
1210
1254
  if (oj_stringio_class == clas) {
1211
- s = rb_funcall2(input, oj_string_id, 0, 0);
1212
- oj_pi_set_input_str(pi, &s);
1255
+ input = rb_funcall2(input, oj_string_id, 0, 0);
1256
+ StringValue(input);
1257
+ oj_pi_set_input_str(pi, &input);
1213
1258
  #if !IS_WINDOWS
1214
1259
  } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
1215
1260
  int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
1216
1261
  ssize_t cnt;
1217
1262
  size_t len = lseek(fd, 0, SEEK_END);
1218
1263
 
1264
+ if ((size_t)-1 == len) {
1265
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
1266
+ }
1219
1267
  lseek(fd, 0, SEEK_SET);
1220
1268
  buf = OJ_R_ALLOC_N(char, len + 1);
1221
1269
  pi->json = buf;
@@ -1261,7 +1309,11 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1261
1309
  // value stack (while it is in scope).
1262
1310
  wrapped_stack = oj_stack_init(&pi->stack);
1263
1311
  rb_protect(protect_parse, (VALUE)pi, &line);
1264
- if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
1312
+ // Only when nothing is on the stack was the input actually empty. A
1313
+ // deferred hash (built at its closing brace from buffered pairs) leaves
1314
+ // head->val Qundef while its entry is still on the stack, e.g. when a
1315
+ // parse error cut the document short; the real error is already set.
1316
+ if (Qundef == pi->stack.head->val && stack_empty(&pi->stack) && !empty_ok(&pi->options)) {
1265
1317
  if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
1266
1318
  oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
1267
1319
  }
@@ -1338,6 +1390,7 @@ CLEANUP:
1338
1390
  if (NULL != pi->json) {
1339
1391
  msg = rb_str_append(msg, rb_utf8_str_new_cstr(" in '"));
1340
1392
  msg = rb_str_append(msg, rb_utf8_str_new_cstr(pi->json));
1393
+ RB_GC_GUARD(input);
1341
1394
  }
1342
1395
  args[0] = msg;
1343
1396
  if (pi->err.clas == oj_parse_error_class) {
@@ -1377,5 +1430,6 @@ CLEANUP:
1377
1430
  break;
1378
1431
  }
1379
1432
  }
1433
+ RB_GC_GUARD(input);
1380
1434
  return result;
1381
1435
  }
data/ext/oj/parse.h CHANGED
@@ -5,6 +5,7 @@
5
5
  #define OJ_PARSE_H
6
6
 
7
7
  #include <stdarg.h>
8
+ #include <stddef.h>
8
9
  #include <stdio.h>
9
10
  #include <string.h>
10
11
 
@@ -80,6 +81,7 @@ extern VALUE oj_num_as_value(NumInfo ni);
80
81
  extern void oj_set_strict_callbacks(ParseInfo pi);
81
82
  extern void oj_set_object_callbacks(ParseInfo pi);
82
83
  extern void oj_set_compat_callbacks(ParseInfo pi);
84
+ extern void oj_compat_array_append_other(VALUE a, VALUE value);
83
85
  extern void oj_set_custom_callbacks(ParseInfo pi);
84
86
  extern void oj_set_wab_callbacks(ParseInfo pi);
85
87
 
@@ -90,11 +92,31 @@ extern VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str);
90
92
  extern VALUE oj_calc_hash_key(ParseInfo pi, Val parent);
91
93
 
92
94
  static inline void parse_info_init(ParseInfo pi) {
93
- memset(pi, 0, sizeof(struct _parseInfo));
95
+ // Zeroing the whole struct costs more than parsing a small document: the
96
+ // embedded reader buffer (rd.base, 4KB) and value stack entries
97
+ // (stack.base, 6.5KB) dominate its 11KB. Both are fully initialized
98
+ // before use — oj_reader_init() for stream parses, oj_stack_init() and
99
+ // stack_push() for the value stack — so zero only the scalars around
100
+ // them.
101
+ memset(pi, 0, offsetof(struct _parseInfo, rd));
102
+ memset((char *)pi + offsetof(struct _parseInfo, rd) + offsetof(struct _reader, head),
103
+ 0,
104
+ offsetof(struct _parseInfo, stack) - offsetof(struct _parseInfo, rd) - offsetof(struct _reader, head));
105
+ memset((char *)pi + offsetof(struct _parseInfo, stack) + offsetof(struct _valStack, head),
106
+ 0,
107
+ sizeof(struct _parseInfo) - offsetof(struct _parseInfo, stack) - offsetof(struct _valStack, head));
94
108
  }
95
109
 
96
110
  extern void oj_scanner_init(void);
97
111
 
112
+ static inline void oj_compat_array_append(VALUE a, VALUE value) {
113
+ if (rb_cArray == RBASIC_CLASS(a)) {
114
+ rb_ary_push(a, value);
115
+ } else {
116
+ oj_compat_array_append_other(a, value);
117
+ }
118
+ }
119
+
98
120
  static inline bool empty_ok(Options options) {
99
121
  switch (options->mode) {
100
122
  case ObjectMode:
data/ext/oj/parser.c CHANGED
@@ -179,8 +179,8 @@ static const char neg_map[258] = "\
179
179
  static const char zero_map[258] = "\
180
180
  .........rs..r..................\
181
181
  r...........u.t.................\
182
- .............................H..\
183
- .............................G..\
182
+ .....w.......................H..\
183
+ .....w.......................G..\
184
184
  ................................\
185
185
  ................................\
186
186
  ................................\
@@ -509,20 +509,29 @@ static void calc_num(ojParser p) {
509
509
  d = -d;
510
510
  }
511
511
  if (0 < p->num.shift) {
512
- d /= pow_map[p->num.shift];
513
- }
514
- if (0 < p->num.exp) {
515
- long double x;
512
+ uint32_t shift = p->num.shift;
516
513
 
517
- if (MAX_POW < p->num.exp) {
518
- x = powl(10.0L, (long double)p->num.exp);
519
- } else {
520
- x = pow_map[p->num.exp];
514
+ while (MAX_POW < shift) {
515
+ d /= pow_map[MAX_POW];
516
+ shift -= MAX_POW;
521
517
  }
518
+ d /= pow_map[shift];
519
+ }
520
+ if (0 < p->num.exp) {
522
521
  if (p->num.exp_neg) {
523
- d /= x;
522
+ int exp = p->num.exp;
523
+
524
+ while (MAX_POW < exp) {
525
+ d /= pow_map[MAX_POW];
526
+ exp -= MAX_POW;
527
+ }
528
+ d /= pow_map[exp];
524
529
  } else {
525
- d *= x;
530
+ if (MAX_POW < p->num.exp) {
531
+ d *= powl(10.0L, (long double)p->num.exp);
532
+ } else {
533
+ d *= pow_map[p->num.exp];
534
+ }
526
535
  }
527
536
  }
528
537
  p->num.dub = d;
@@ -559,19 +568,31 @@ static void big_change(ojParser p) {
559
568
  break;
560
569
  case OJ_DECIMAL: {
561
570
  int shift = p->num.shift;
571
+ int end = sizeof(buf) - 1;
562
572
 
563
- for (len = sizeof(buf) - 1; 0 < i; len--, i /= 10, shift--) {
564
- if (0 == shift) {
565
- buf[len] = '.';
566
- len--;
567
- }
568
- buf[len] = '0' + (i % 10);
569
- }
573
+ len = end;
574
+ do {
575
+ buf[--len] = '0' + (i % 10);
576
+ i /= 10;
577
+ } while (0 < i);
570
578
  if (p->num.neg) {
571
- buf[len] = '-';
572
- len--;
579
+ buf_append(&p->buf, '-');
580
+ }
581
+ if (end - len <= shift) {
582
+ buf_append_string(&p->buf, "0.", 2);
583
+ for (int cnt = shift - (end - len); 0 < cnt; cnt--) {
584
+ buf_append(&p->buf, '0');
585
+ }
586
+ buf_append_string(&p->buf, buf + len, end - len);
587
+ } else {
588
+ int decimal = end - shift;
589
+
590
+ buf_append_string(&p->buf, buf + len, decimal - len);
591
+ if (0 < shift) {
592
+ buf_append(&p->buf, '.');
593
+ buf_append_string(&p->buf, buf + decimal, shift);
594
+ }
573
595
  }
574
- buf_append_string(&p->buf, buf + len + 1, sizeof(buf) - len - 1);
575
596
  if (0 < p->num.exp) {
576
597
  int x = p->num.exp;
577
598
  int d, div;
@@ -585,6 +606,7 @@ static void big_change(ojParser p) {
585
606
  d = x / div % 10;
586
607
  if (started || 0 < d) {
587
608
  buf_append(&p->buf, '0' + d);
609
+ started = true;
588
610
  }
589
611
  }
590
612
  }
@@ -740,6 +762,12 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
740
762
  calc_num(p);
741
763
  // flow through
742
764
  case CLOSE_OBJECT:
765
+ // Inside an object value_map is only in use right after a colon.
766
+ if (value_map == p->map && 0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
767
+ p->col = b - json - p->col + 1;
768
+ parse_error(p, "expected a value, not an object close");
769
+ return;
770
+ }
743
771
  p->map = (1 == p->depth) ? value_map : after_map;
744
772
  if (p->depth <= 0 || OBJECT_FUN != p->stack[p->depth]) {
745
773
  p->col = b - json - p->col + 1;
@@ -859,6 +887,11 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
859
887
  p->num.shift++;
860
888
  } else {
861
889
  big_change(p);
890
+ if (0 == p->num.shift) {
891
+ // No fraction digit was read yet so big_change()
892
+ // did not add the '.' before the digits that follow.
893
+ buf_append(&p->buf, '.');
894
+ }
862
895
  p->map = big_frac_map;
863
896
  break;
864
897
  }
@@ -871,6 +904,7 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
871
904
  break;
872
905
  case NUM_ZERO: p->map = zero_map; break;
873
906
  case NEG_DIGIT:
907
+ p->map = digit_map;
874
908
  for (; NUM_DIGIT == digit_map[*b]; b++) {
875
909
  uint64_t x = p->num.fixnum * 10 + (uint64_t)(*b - '0');
876
910
 
@@ -883,7 +917,6 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
883
917
  }
884
918
  }
885
919
  b--;
886
- p->map = digit_map;
887
920
  break;
888
921
  case EXP_SIGN:
889
922
  p->num.exp_neg = ('-' == *b);
@@ -942,10 +975,12 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
942
975
  case NUM_SPC:
943
976
  p->cur = b - json;
944
977
  calc_num(p);
978
+ p->map = (0 == p->depth) ? value_map : after_map;
945
979
  break;
946
980
  case NUM_NEWLINE:
947
981
  p->cur = b - json;
948
982
  calc_num(p);
983
+ p->map = (0 == p->depth) ? value_map : after_map;
949
984
  b++;
950
985
  #ifdef SPACE_JUMP
951
986
  // for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
@@ -988,15 +1023,26 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
988
1023
  p->ri++;
989
1024
  p->ucode = p->ucode << 4 | (uint32_t)hex_map[*b];
990
1025
  if (4 <= p->ri) {
991
- byte utf8[8];
992
- size_t ulen = unicodeToUtf8(p->ucode, utf8);
1026
+ byte utf8[8];
1027
+ Buf buf = (':' == p->next_map[256]) ? &p->key : &p->buf;
1028
+ uint32_t code = p->ucode;
993
1029
 
994
- if (0 < ulen) {
995
- if (':' == p->next_map[256]) {
996
- buf_append_string(&p->key, (const char *)utf8, ulen);
997
- } else {
998
- buf_append_string(&p->buf, (const char *)utf8, ulen);
1030
+ // A low surrogate right after a high one, which the previous
1031
+ // escape appended on its own, completes a pair.
1032
+ if (0xDC00 <= code && code <= 0xDFFF && 3 <= buf_len(buf)) {
1033
+ const byte *hi = (const byte *)buf->tail - 3;
1034
+
1035
+ if (0xED == hi[0] && 0xA0 <= hi[1] && hi[1] <= 0xAF) {
1036
+ uint32_t c1 = ((uint32_t)(hi[1] & 0x0F) << 6) | (hi[2] & 0x3F);
1037
+
1038
+ code = ((c1 << 10) | (code - 0xDC00)) + 0x00010000;
1039
+ buf->tail -= 3;
999
1040
  }
1041
+ }
1042
+ size_t ulen = unicodeToUtf8(code, utf8);
1043
+
1044
+ if (0 < ulen) {
1045
+ buf_append_string(buf, (const char *)utf8, ulen);
1000
1046
  } else {
1001
1047
  parse_error(p, "invalid unicode");
1002
1048
  return;
@@ -1186,11 +1232,9 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
1186
1232
  case '0':
1187
1233
  case 'd':
1188
1234
  case 'f':
1189
- case 'z':
1190
1235
  case 'X':
1191
1236
  case 'D':
1192
1237
  case 'g':
1193
- case 'B':
1194
1238
  case 'Y':
1195
1239
  p->cur = b - json;
1196
1240
  calc_num(p);
@@ -1440,6 +1484,23 @@ static void validate_primitives_are_complete(ojParser p) {
1440
1484
  }
1441
1485
  }
1442
1486
 
1487
+ // A top level number that stops after a '-', a '.', an 'e' or an exponent
1488
+ // sign is still waiting for a digit.
1489
+ static void validate_number_is_complete(ojParser p) {
1490
+ if (0 < p->depth) {
1491
+ return;
1492
+ }
1493
+ switch (p->map[256]) {
1494
+ case '-':
1495
+ case '.':
1496
+ case 'x':
1497
+ case 'z':
1498
+ case 'o':
1499
+ case 'B':
1500
+ case 'Z': parse_error(p, "incomplete number"); break;
1501
+ }
1502
+ }
1503
+
1443
1504
  static void validate_non_primitives_are_complete(ojParser p) {
1444
1505
  if (0 >= p->depth) {
1445
1506
  return;
@@ -1453,6 +1514,7 @@ static void validate_non_primitives_are_complete(ojParser p) {
1453
1514
 
1454
1515
  static void validate_document_end(ojParser p) {
1455
1516
  validate_primitives_are_complete(p);
1517
+ validate_number_is_complete(p);
1456
1518
  validate_non_primitives_are_complete(p);
1457
1519
  }
1458
1520
 
@@ -1465,19 +1527,20 @@ static void validate_document_end(ojParser p) {
1465
1527
  */
1466
1528
  static VALUE parser_parse(VALUE self, VALUE json) {
1467
1529
  ojParser p;
1468
- int frozen = OBJ_FROZEN(json);
1469
1530
  const byte *ptr;
1470
1531
 
1471
- if (!frozen) {
1532
+ StringValue(json);
1533
+ if (!OBJ_FROZEN(json)) {
1472
1534
  rb_str_freeze(json);
1473
1535
  }
1474
- ptr = (const byte *)StringValuePtr(json);
1536
+ ptr = (const byte *)RSTRING_PTR(json);
1475
1537
 
1476
1538
  TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1477
1539
 
1478
1540
  parser_reset(p);
1479
1541
  p->start(p);
1480
1542
  parse(p, ptr, (size_t)RSTRING_LEN(json), false);
1543
+ RB_GC_GUARD(json);
1481
1544
  validate_document_end(p);
1482
1545
 
1483
1546
  return p->result(p);
@@ -1577,7 +1640,7 @@ static VALUE parser_file(VALUE self, VALUE filename) {
1577
1640
 
1578
1641
  TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1579
1642
 
1580
- path = StringValuePtr(filename);
1643
+ path = StringValueCStr(filename);
1581
1644
 
1582
1645
  parser_reset(p);
1583
1646
  p->start(p);
data/ext/oj/parser.h CHANGED
@@ -34,7 +34,7 @@ typedef struct _num {
34
34
  uint32_t len;
35
35
  int16_t div; // 10^div
36
36
  int16_t exp;
37
- uint8_t shift; // shift of fixnum to get decimal
37
+ uint32_t shift; // shift of fixnum to get decimal
38
38
  bool neg;
39
39
  bool exp_neg;
40
40
  // for numbers as strings, reuse buf
data/ext/oj/rails.c CHANGED
@@ -1062,6 +1062,7 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
1062
1062
  }
1063
1063
  if (Yes == copts.circular) {
1064
1064
  oj_cache8_delete(out.circ_cache);
1065
+ out.circ_cache = NULL;
1065
1066
  }
1066
1067
 
1067
1068
  oj_out_free(&out);
@@ -1316,12 +1317,15 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1316
1317
  size_t cnt = 0;
1317
1318
 
1318
1319
  if (0.0 == d) {
1319
- b = buf;
1320
+ b = buf;
1321
+ if (signbit(d)) {
1322
+ *b++ = '-';
1323
+ }
1320
1324
  *b++ = '0';
1321
1325
  *b++ = '.';
1322
1326
  *b++ = '0';
1323
- *b++ = '\0';
1324
- cnt = 3;
1327
+ *b = '\0';
1328
+ cnt = b - buf;
1325
1329
  } else {
1326
1330
  if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) {
1327
1331
  strcpy(buf, "null");
@@ -1372,6 +1376,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1372
1376
  cnt--;
1373
1377
  for (i = 0; i <= cnt; i++) {
1374
1378
  if (out->opts->dump_opts.use) {
1379
+ assure_size(out, size);
1375
1380
  if (0 < out->opts->dump_opts.array_size) {
1376
1381
  APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1377
1382
  }
data/ext/oj/reader.c CHANGED
@@ -45,6 +45,7 @@ void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) {
45
45
  reader->line = 1;
46
46
  reader->col = 0;
47
47
  reader->free_head = 0;
48
+ reader->in_val = Qnil;
48
49
 
49
50
  if (0 != fd) {
50
51
  reader->read_func = read_from_fd;
@@ -52,6 +53,7 @@ void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) {
52
53
  } else if (rb_cString == io_class) {
53
54
  reader->read_func = 0;
54
55
  reader->in_str = StringValuePtr(io);
56
+ reader->in_val = io;
55
57
  reader->head = (char *)reader->in_str;
56
58
  reader->tail = reader->head;
57
59
  reader->read_end = reader->head + RSTRING_LEN(io);
@@ -60,6 +62,7 @@ void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) {
60
62
 
61
63
  reader->read_func = 0;
62
64
  reader->in_str = StringValuePtr(s);
65
+ reader->in_val = s;
63
66
  reader->head = (char *)reader->in_str;
64
67
  reader->tail = reader->head;
65
68
  reader->read_end = reader->head + RSTRING_LEN(s);
@@ -79,6 +82,7 @@ void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) {
79
82
 
80
83
  reader->read_func = 0;
81
84
  reader->in_str = StringValuePtr(rstr);
85
+ reader->in_val = rstr;
82
86
  reader->head = (char *)reader->in_str;
83
87
  reader->tail = reader->head;
84
88
  reader->read_end = reader->head + RSTRING_LEN(rstr);
data/ext/oj/reader.h CHANGED
@@ -24,6 +24,7 @@ typedef struct _reader {
24
24
  VALUE io;
25
25
  const char *in_str;
26
26
  };
27
+ VALUE in_val;
27
28
  } *Reader;
28
29
 
29
30
  extern void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s);
data/ext/oj/resolve.c CHANGED
@@ -82,8 +82,9 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE
82
82
 
83
83
  VALUE
84
84
  oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class) {
85
- size_t len = RSTRING_LEN(nameVal);
86
- const char *str = StringValuePtr(nameVal);
87
-
88
- return resolve_classpath(pi, str, len, 0, error_class);
85
+ if (T_STRING != rb_type(nameVal)) {
86
+ oj_set_error_at(pi, error_class, __FILE__, __LINE__, "Invalid struct data");
87
+ return Qundef;
88
+ }
89
+ return resolve_classpath(pi, RSTRING_PTR(nameVal), RSTRING_LEN(nameVal), 0, error_class);
89
90
  }
data/ext/oj/resolve.h CHANGED
@@ -4,9 +4,18 @@
4
4
  #ifndef OJ_RESOLVE_H
5
5
  #define OJ_RESOLVE_H
6
6
 
7
+ #include <stdbool.h>
8
+ #include <string.h>
9
+
7
10
  #include "ruby.h"
8
11
 
9
12
  extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class);
10
13
  extern VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class);
11
14
 
15
+ inline static bool oj_is_backtrace_name(const char *name, size_t len) {
16
+ static const char backtrace[] = "Thread::Backtrace";
17
+
18
+ return sizeof(backtrace) - 1 == len && 0 == memcmp(backtrace, name, len);
19
+ }
20
+
12
21
  #endif /* OJ_RESOLVE_H */
data/ext/oj/saj.c CHANGED
@@ -646,13 +646,14 @@ static VALUE protect_saj_parse(VALUE x) {
646
646
  */
647
647
  VALUE
648
648
  oj_saj_parse(int argc, VALUE *argv, VALUE self) {
649
- char *json = 0;
650
- size_t len = 0;
651
- VALUE input = argv[1];
649
+ char *json = 0;
650
+ size_t len = 0;
651
+ VALUE input;
652
652
 
653
653
  if (argc < 2) {
654
654
  rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
655
655
  }
656
+ input = argv[1];
656
657
  if (rb_type(input) == T_STRING) {
657
658
  // the json string gets modified so make a copy of it
658
659
  len = RSTRING_LEN(input) + 1;
@@ -663,16 +664,20 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
663
664
  volatile VALUE s;
664
665
 
665
666
  if (oj_stringio_class == clas) {
666
- s = rb_funcall2(input, oj_string_id, 0, 0);
667
+ s = rb_funcall2(input, oj_string_id, 0, 0);
668
+ StringValueCStr(s);
667
669
  len = RSTRING_LEN(s) + 1;
668
670
  json = OJ_R_ALLOC_N(char, len);
669
- strcpy(json, StringValueCStr(s));
671
+ strcpy(json, RSTRING_PTR(s));
670
672
  #if !IS_WINDOWS
671
673
  } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
672
674
  int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
673
675
  ssize_t cnt;
674
676
 
675
677
  len = lseek(fd, 0, SEEK_END);
678
+ if ((size_t)-1 == len) {
679
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
680
+ }
676
681
  lseek(fd, 0, SEEK_SET);
677
682
  json = OJ_R_ALLOC_N(char, len + 1);
678
683
  {
@@ -681,6 +686,7 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
681
686
  while (total < len) {
682
687
  cnt = read(fd, json + total, len - total);
683
688
  if (cnt <= 0) {
689
+ OJ_R_FREE(json);
684
690
  rb_raise(rb_eIOError, "failed to read from IO Object.");
685
691
  }
686
692
  total += cnt;
@@ -689,10 +695,11 @@ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
689
695
  json[len] = '\0';
690
696
  #endif
691
697
  } else if (rb_respond_to(input, oj_read_id)) {
692
- s = rb_funcall2(input, oj_read_id, 0, 0);
698
+ s = rb_funcall2(input, oj_read_id, 0, 0);
699
+ StringValueCStr(s);
693
700
  len = RSTRING_LEN(s) + 1;
694
701
  json = OJ_R_ALLOC_N(char, len);
695
- strcpy(json, StringValueCStr(s));
702
+ strcpy(json, RSTRING_PTR(s));
696
703
  } else {
697
704
  rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
698
705
  }