@@ -37,7 +37,7 @@ static ID i_chr, i_aset, i_aref,
3737 i_leftshift , i_new , i_try_convert , i_uminus , i_encode ;
3838
3939static VALUE sym_max_nesting , sym_allow_nan , sym_allow_trailing_comma , sym_symbolize_names , sym_freeze ,
40- sym_decimal_class , sym_on_load ;
40+ sym_decimal_class , sym_on_load , sym_allow_duplicate_key ;
4141
4242static int binary_encindex ;
4343static int utf8_encindex ;
@@ -365,10 +365,17 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
365365 return len ;
366366}
367367
368+ enum duplicate_key_action {
369+ JSON_DEPRECATED = 0 ,
370+ JSON_IGNORE ,
371+ JSON_RAISE ,
372+ };
373+
368374typedef struct JSON_ParserStruct {
369375 VALUE on_load_proc ;
370376 VALUE decimal_class ;
371377 ID decimal_method_id ;
378+ enum duplicate_key_action on_duplicate_key ;
372379 int max_nesting ;
373380 bool allow_nan ;
374381 bool allow_trailing_comma ;
@@ -388,15 +395,8 @@ typedef struct JSON_ParserStateStruct {
388395 int current_nesting ;
389396} JSON_ParserState ;
390397
391-
392- #define PARSE_ERROR_FRAGMENT_LEN 32
393- #ifdef RBIMPL_ATTR_NORETURN
394- RBIMPL_ATTR_NORETURN ()
395- #endif
396- static void raise_parse_error (const char * format , JSON_ParserState * state )
398+ static void cursor_position (JSON_ParserState * state , long * line_out , long * column_out )
397399{
398- unsigned char buffer [PARSE_ERROR_FRAGMENT_LEN + 3 ];
399-
400400 const char * cursor = state -> cursor ;
401401 long column = 0 ;
402402 long line = 1 ;
@@ -413,6 +413,27 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
413413 line ++ ;
414414 }
415415 }
416+ * line_out = line ;
417+ * column_out = column ;
418+ }
419+
420+ static void emit_parse_warning (const char * message , JSON_ParserState * state )
421+ {
422+ long line , column ;
423+ cursor_position (state , & line , & column );
424+
425+ rb_warn ("%s at line %ld column %ld" , message , line , column );
426+ }
427+
428+ #define PARSE_ERROR_FRAGMENT_LEN 32
429+ #ifdef RBIMPL_ATTR_NORETURN
430+ RBIMPL_ATTR_NORETURN ()
431+ #endif
432+ static void raise_parse_error (const char * format , JSON_ParserState * state )
433+ {
434+ unsigned char buffer [PARSE_ERROR_FRAGMENT_LEN + 3 ];
435+ long line , column ;
436+ cursor_position (state , & line , & column );
416437
417438 const char * ptr = "EOF" ;
418439 if (state -> cursor && state -> cursor < state -> end ) {
@@ -809,11 +830,25 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
809830 return array ;
810831}
811832
812- static inline VALUE json_decode_object (JSON_ParserState * state , JSON_ParserConfig * config , long count )
833+ static inline VALUE json_decode_object (JSON_ParserState * state , JSON_ParserConfig * config , size_t count )
813834{
814- VALUE object = rb_hash_new_capa (count );
835+ size_t entries_count = count / 2 ;
836+ VALUE object = rb_hash_new_capa (entries_count );
815837 rb_hash_bulk_insert (count , rvalue_stack_peek (state -> stack , count ), object );
816838
839+ if (RB_UNLIKELY (RHASH_SIZE (object ) < entries_count )) {
840+ switch (config -> on_duplicate_key ) {
841+ case JSON_IGNORE :
842+ break ;
843+ case JSON_DEPRECATED :
844+ emit_parse_warning ("detected duplicate keys in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`" , state );
845+ break ;
846+ case JSON_RAISE :
847+ raise_parse_error ("duplicate key" , state );
848+ break ;
849+ }
850+ }
851+
817852 rvalue_stack_pop (state -> stack , count );
818853
819854 if (config -> freeze ) {
@@ -1101,6 +1136,8 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
11011136 break ;
11021137 }
11031138 case '{' : {
1139+ const char * object_start_cursor = state -> cursor ;
1140+
11041141 state -> cursor ++ ;
11051142 json_eat_whitespace (state );
11061143 long stack_head = state -> stack -> head ;
@@ -1135,8 +1172,15 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
11351172 if (* state -> cursor == '}' ) {
11361173 state -> cursor ++ ;
11371174 state -> current_nesting -- ;
1138- long count = state -> stack -> head - stack_head ;
1139- return json_push_value (state , config , json_decode_object (state , config , count ));
1175+ size_t count = state -> stack -> head - stack_head ;
1176+
1177+ // Temporary rewind cursor in case an error is raised
1178+ const char * final_cursor = state -> cursor ;
1179+ state -> cursor = object_start_cursor ;
1180+ VALUE object = json_decode_object (state , config , count );
1181+ state -> cursor = final_cursor ;
1182+
1183+ return json_push_value (state , config , object );
11401184 }
11411185
11421186 if (* state -> cursor == ',' ) {
@@ -1225,6 +1269,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
12251269 else if (key == sym_symbolize_names ) { config -> symbolize_names = RTEST (val ); }
12261270 else if (key == sym_freeze ) { config -> freeze = RTEST (val ); }
12271271 else if (key == sym_on_load ) { config -> on_load_proc = RTEST (val ) ? val : Qfalse ; }
1272+ else if (key == sym_allow_duplicate_key ) { config -> on_duplicate_key = RTEST (val ) ? JSON_IGNORE : JSON_RAISE ; }
12281273 else if (key == sym_decimal_class ) {
12291274 if (RTEST (val )) {
12301275 if (rb_respond_to (val , i_try_convert )) {
@@ -1441,6 +1486,7 @@ void Init_parser(void)
14411486 sym_freeze = ID2SYM (rb_intern ("freeze" ));
14421487 sym_on_load = ID2SYM (rb_intern ("on_load" ));
14431488 sym_decimal_class = ID2SYM (rb_intern ("decimal_class" ));
1489+ sym_allow_duplicate_key = ID2SYM (rb_intern ("allow_duplicate_key" ));
14441490
14451491 i_chr = rb_intern ("chr" );
14461492 i_aset = rb_intern ("[]=" );
0 commit comments