json 2.21.2 → 3.0.1

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.
@@ -5,7 +5,7 @@
5
5
  static VALUE mJSON, eNestingError, eParserError, Encoding_UTF_8;
6
6
  static VALUE CNaN, CInfinity, CMinusInfinity, JSON_empty_string;
7
7
 
8
- static ID i_new, i_try_convert, i_encode, i_at_line, i_at_column;
8
+ static ID i_new, i_try_convert, i_encode, i_at_line, i_at_column, i_at_json_path;
9
9
  #ifndef HAVE_RB_STR_TO_INTERNED_STR
10
10
  static ID i_uminus;
11
11
  #endif
@@ -403,19 +403,13 @@ typedef struct json_frame_stack_struct {
403
403
  json_frame *ptr;
404
404
  } json_frame_stack;
405
405
 
406
- enum deprecatable_action {
407
- JSON_DEPRECATED = 0,
408
- JSON_IGNORE,
409
- JSON_RAISE,
410
- };
411
-
412
406
  typedef struct JSON_ParserStruct {
413
407
  VALUE on_load_proc;
414
408
  VALUE decimal_class;
415
409
  ID decimal_method_id;
416
- enum deprecatable_action on_duplicate_key;
417
- enum deprecatable_action on_comment;
418
410
  int max_nesting;
411
+ bool allow_comments;
412
+ bool allow_duplicate_key;
419
413
  bool allow_nan;
420
414
  bool allow_trailing_comma;
421
415
  bool allow_control_characters;
@@ -435,7 +429,6 @@ typedef struct JSON_ParserStateStruct {
435
429
  rvalue_cache name_cache;
436
430
  int in_array;
437
431
  int current_nesting;
438
- unsigned int emitted_deprecations;
439
432
  VALUE parser;
440
433
  } JSON_ParserState;
441
434
 
@@ -619,21 +612,6 @@ static void cursor_position(JSON_ParserState *state, long *line_out, long *colum
619
612
  *column_out = column;
620
613
  }
621
614
 
622
- static const unsigned int MAX_DEPRECATIONS = 5;
623
-
624
- static void emit_parse_warning(const char *message, JSON_ParserState *state)
625
- {
626
- VALUE warning;
627
- if (state->parser) { // line and columns can't be accurate in resumable
628
- warning = rb_utf8_str_new_cstr(message);
629
- } else {
630
- long line, column;
631
- cursor_position(state, &line, &column);
632
- warning = rb_sprintf("%s at line %ld column %ld", message, line, column);
633
- }
634
- rb_funcall(mJSON, rb_intern("deprecation_warning"), 1, warning);
635
- }
636
-
637
615
  #define PARSE_ERROR_FRAGMENT_LEN 32
638
616
 
639
617
  static VALUE build_parse_error_message(const char *format, JSON_ParserState *state)
@@ -673,11 +651,42 @@ static VALUE build_parse_error_message(const char *format, JSON_ParserState *sta
673
651
  return rb_enc_sprintf(enc_utf8, format, ptr);
674
652
  }
675
653
 
654
+ static VALUE json_path_new(JSON_ParserState *state, VALUE duplicate_key)
655
+ {
656
+ VALUE path = rb_ary_new_capa(state->current_nesting);
657
+
658
+ json_frame_stack *frames = state->frames;
659
+ rvalue_stack *values = state->value_stack;
660
+
661
+ for (long depth = 1; depth < frames->head; depth++) {
662
+ json_frame *frame = &frames->ptr[depth];
663
+
664
+ bool innermost = depth == frames->head - 1;
665
+ long child_head = innermost ? values->head : frames->ptr[depth + 1].value_stack_head;
666
+ long count = child_head - frame->value_stack_head;
667
+
668
+ if (frame->type == JSON_FRAME_ARRAY) {
669
+ rb_ary_push(path, LONG2NUM(frame->phase == JSON_PHASE_ARRAY_COMMA ? count - 1 : count));
670
+ } else if (innermost && !UNDEF_P(duplicate_key)) {
671
+ rb_ary_push(path, duplicate_key);
672
+ } else if (count & 1) {
673
+ rb_ary_push(path, values->ptr[child_head - 1]);
674
+ } else if (frame->phase == JSON_PHASE_OBJECT_COMMA && count >= 2) {
675
+ rb_ary_push(path, values->ptr[child_head - 2]);
676
+ } else {
677
+ break;
678
+ }
679
+ }
680
+
681
+ return path;
682
+ }
683
+
676
684
  static VALUE parse_error_new(JSON_ParserState *state, VALUE message, long line, long column, bool eos)
677
685
  {
678
686
  VALUE exc = rb_exc_new_str(eParserError, message);
679
687
  rb_ivar_set(exc, i_at_line, LONG2NUM(line));
680
688
  rb_ivar_set(exc, i_at_column, LONG2NUM(column));
689
+ rb_ivar_set(exc, i_at_json_path, json_path_new(state, Qundef));
681
690
  return exc;
682
691
  }
683
692
 
@@ -772,11 +781,10 @@ static uint32_t unescape_unicode(JSON_ParserState *state, const char *sp, const
772
781
 
773
782
  static const rb_data_type_t JSON_ParserConfig_type;
774
783
 
775
- const char *COMMENT_DEPRECATION_MESSAGE = "Encountered comment in JSON. This will raise an error in json 3.0 unless enabled via `allow_comments: true`";
776
784
  NOINLINE(static) void
777
785
  json_eat_comments(JSON_ParserState *state, JSON_ParserConfig *config, const char *resume_pos)
778
786
  {
779
- if (config->on_comment == JSON_RAISE) {
787
+ if (!config->allow_comments) {
780
788
  raise_syntax_error("unexpected token %s", state);
781
789
  }
782
790
 
@@ -826,11 +834,6 @@ json_eat_comments(JSON_ParserState *state, JSON_ParserConfig *config, const char
826
834
  raise_parse_error_at("unexpected token %s", state, eos(state) ? rewind_pos : start, eos(state));
827
835
  break;
828
836
  }
829
-
830
- if (config->on_comment == JSON_DEPRECATED && state->emitted_deprecations < MAX_DEPRECATIONS) {
831
- state->emitted_deprecations++;
832
- emit_parse_warning(COMMENT_DEPRECATION_MESSAGE, state);
833
- }
834
837
  }
835
838
 
836
839
  ALWAYS_INLINE(static) void
@@ -1038,6 +1041,9 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
1038
1041
  raise_syntax_error_at("incomplete surrogate pair at %s", state, p);
1039
1042
  break;
1040
1043
  }
1044
+ } else if ((ch & 0xFC00) == 0xDC00) {
1045
+ raise_syntax_error_at("unpaired trailing surrogate at %s", state, p);
1046
+ break;
1041
1047
  }
1042
1048
 
1043
1049
  int unescape_len = convert_UTF32_to_UTF8(buffer, ch);
@@ -1082,7 +1088,8 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
1082
1088
  return result;
1083
1089
  }
1084
1090
 
1085
- #define MAX_FAST_INTEGER_SIZE 18
1091
+ #define MAX_FAST_INTEGER_SIZE 19
1092
+ #define MAX_FAST_UINT64_SIZE 20
1086
1093
  #define MAX_NUMBER_STACK_BUFFER 128
1087
1094
 
1088
1095
  typedef VALUE (*json_number_decode_func_t)(const char *ptr);
@@ -1117,11 +1124,30 @@ NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
1117
1124
 
1118
1125
  static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
1119
1126
  {
1120
- if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
1121
- if (negative) {
1127
+ if (RB_LIKELY(mantissa_digits <= MAX_FAST_INTEGER_SIZE)) {
1128
+ if (RB_LIKELY(!negative)) {
1129
+ return UINT64T2NUM(mantissa);
1130
+ }
1131
+
1132
+ // For a negative number 19 digits in length, we only get half of the range,
1133
+ // so ensure this negative number is less than INT64_MAX.
1134
+ //
1135
+ // Note: This does miss INT64_MIN as it's value is one past INT64_MAX
1136
+ // when converted to a uint64_t. It will still be parsed correctly by
1137
+ // falling through to json_decode_large_integer.
1138
+ if (RB_LIKELY(mantissa <= (uint64_t)INT64_MAX)) {
1122
1139
  return INT64T2NUM(-((int64_t)mantissa));
1123
1140
  }
1124
- return UINT64T2NUM(mantissa);
1141
+ }
1142
+
1143
+ if (!negative && mantissa_digits == MAX_FAST_UINT64_SIZE) {
1144
+ // Not all 20 digit integers can be safely represented by a uint64_t but
1145
+ // some can. The memcmp with uint64_max is safe as we've rejected leading
1146
+ // zeros and we have guaranteed we're comparing it with a 20 digit number.
1147
+ static const char uint64_max[] = "18446744073709551615";
1148
+ if (memcmp(end - MAX_FAST_UINT64_SIZE, uint64_max, MAX_FAST_UINT64_SIZE) <= 0) {
1149
+ return UINT64T2NUM(mantissa);
1150
+ }
1125
1151
  }
1126
1152
 
1127
1153
  return json_decode_large_integer(start, end - start);
@@ -1199,17 +1225,6 @@ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
1199
1225
  return Qfalse;
1200
1226
  }
1201
1227
 
1202
- NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
1203
- {
1204
- VALUE message = rb_sprintf(
1205
- "detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
1206
- rb_inspect(duplicate_key)
1207
- );
1208
-
1209
- emit_parse_warning(RSTRING_PTR(message), state);
1210
- RB_GC_GUARD(message);
1211
- }
1212
-
1213
1228
  NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
1214
1229
  {
1215
1230
  VALUE message = rb_sprintf(
@@ -1218,35 +1233,24 @@ NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE d
1218
1233
  );
1219
1234
 
1220
1235
  rb_str_concat(message, build_parse_error_message("", state));
1236
+ VALUE exc;
1221
1237
  if (state->parser) { // line and columns can't be accurate in resumable
1222
- rb_exc_raise(parse_error_new(state, message, 0, 0, false));
1238
+ exc = parse_error_new(state, message, 0, 0, false);
1223
1239
  } else {
1224
1240
  long line, column;
1225
1241
  cursor_position(state, &line, &column);
1226
1242
  rb_str_catf(message, " at line %ld column %ld", line, column);
1227
- rb_exc_raise(parse_error_new(state, message, line, column, false));
1243
+ exc = parse_error_new(state, message, line, column, false);
1228
1244
  }
1245
+ rb_ivar_set(exc, i_at_json_path, json_path_new(state, duplicate_key));
1246
+ rb_exc_raise(exc);
1229
1247
  }
1230
1248
 
1231
1249
  NOINLINE(static) void json_on_duplicate_key(JSON_ParserState *state, JSON_ParserConfig *config, size_t count, const VALUE *pairs)
1232
1250
  {
1233
- switch (config->on_duplicate_key) {
1234
- case JSON_IGNORE:
1235
- return;
1236
-
1237
- case JSON_DEPRECATED:
1238
- // Only emit the first few deprecations to avoid spamming.
1239
- if (state->emitted_deprecations < MAX_DEPRECATIONS) {
1240
- state->emitted_deprecations++;
1241
- emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
1242
- }
1243
- return;
1244
-
1245
- case JSON_RAISE:
1246
- raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
1247
- return;
1251
+ if (!config->allow_duplicate_key) {
1252
+ raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
1248
1253
  }
1249
- UNREACHABLE;
1250
1254
  }
1251
1255
 
1252
1256
  static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
@@ -2012,13 +2016,13 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
2012
2016
  if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
2013
2017
  else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
2014
2018
  else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
2015
- else if (key == sym_allow_comments) { config->on_comment = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
2019
+ else if (key == sym_allow_comments) { config->allow_comments = RTEST(val); }
2016
2020
  else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
2017
2021
  else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
2018
2022
  else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
2019
2023
  else if (key == sym_freeze) { config->freeze = RTEST(val); }
2020
2024
  else if (key == sym_on_load) { parser_config_wb_write(self, &config->on_load_proc, RTEST(val) ? val : Qfalse); }
2021
- else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
2025
+ else if (key == sym_allow_duplicate_key) { config->allow_duplicate_key = RTEST(val); }
2022
2026
  else if (key == sym_decimal_class) {
2023
2027
  if (RTEST(val)) {
2024
2028
  if (rb_respond_to(val, i_try_convert)) {
@@ -2048,7 +2052,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
2048
2052
  }
2049
2053
  }
2050
2054
  }
2051
- else if (args->strict) {
2055
+ else {
2052
2056
  if (!args->unknown_keywords) {
2053
2057
  args->unknown_keywords = rb_obj_hide(rb_ary_new());
2054
2058
  }
@@ -2076,15 +2080,7 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts, VALUE self
2076
2080
  // the provided keys than to check all possible keys.
2077
2081
  rb_hash_foreach(opts, parser_config_init_i, (VALUE)&args);
2078
2082
 
2079
- if (RB_UNLIKELY(args.unknown_keywords)) {
2080
- if (RARRAY_LEN(args.unknown_keywords) == 1) {
2081
- rb_raise(rb_eArgError, "unknown keyword: %" PRIsVALUE, RARRAY_AREF(args.unknown_keywords, 0));
2082
- }
2083
- else {
2084
- VALUE keywords = rb_ary_join(args.unknown_keywords, rb_utf8_str_new_cstr(", "));
2085
- rb_raise(rb_eArgError, "unknown keywords: %" PRIsVALUE, keywords);
2086
- }
2087
- }
2083
+ raise_argument_error_on_unknown_keywords(args.unknown_keywords);
2088
2084
  }
2089
2085
 
2090
2086
  /*
@@ -2163,6 +2159,12 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE src)
2163
2159
  // the rvalue stack.
2164
2160
  VALUE result = complete ? *rvalue_stack_peek(state->value_stack, 1) : Qundef;
2165
2161
 
2162
+ if (complete) {
2163
+ json_ensure_eof(state, config);
2164
+ } else {
2165
+ raise_eos_error("unexpected end of input", state);
2166
+ }
2167
+
2166
2168
  // This may be skipped in case of exception, but
2167
2169
  // it won't cause a leak.
2168
2170
  rvalue_stack_eagerly_release(value_stack_handle);
@@ -2171,12 +2173,6 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE src)
2171
2173
  RB_GC_GUARD(frame_stack_handle);
2172
2174
  RB_GC_GUARD(Vsource);
2173
2175
 
2174
- if (complete) {
2175
- json_ensure_eof(state, config);
2176
- } else {
2177
- raise_eos_error("unexpected end of input", state);
2178
- }
2179
-
2180
2176
  return result;
2181
2177
  }
2182
2178
 
@@ -2646,7 +2642,6 @@ static VALUE cResumableParser_clear(VALUE self)
2646
2642
  parser->state.name_cache.length = 0;
2647
2643
  parser->state.current_nesting = 0;
2648
2644
  parser->state.in_array = 1;
2649
- parser->state.emitted_deprecations = 0;
2650
2645
  parser->state.start = parser->state.cursor = parser->state.end = NULL;
2651
2646
  return self;
2652
2647
  }
@@ -2913,6 +2908,7 @@ void Init_parser(void)
2913
2908
  i_encode = rb_intern("encode");
2914
2909
  i_at_line = rb_intern("@line");
2915
2910
  i_at_column = rb_intern("@column");
2911
+ i_at_json_path = rb_intern("@json_path");
2916
2912
 
2917
2913
  binary_encindex = rb_ascii8bit_encindex();
2918
2914
  utf8_encindex = rb_utf8_encindex();