@@ -426,6 +426,7 @@ static void emit_parse_warning(const char *message, JSON_ParserState *state)
426426}
427427
428428#define PARSE_ERROR_FRAGMENT_LEN 32
429+
429430#ifdef RBIMPL_ATTR_NORETURN
430431RBIMPL_ATTR_NORETURN ()
431432#endif
@@ -830,21 +831,64 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
830831 return array ;
831832}
832833
834+ static VALUE json_find_duplicated_key (size_t count , const VALUE * pairs )
835+ {
836+ VALUE set = rb_hash_new_capa (count / 2 );
837+ for (size_t index = 0 ; index < count ; index += 2 ) {
838+ size_t before = RHASH_SIZE (set );
839+ VALUE key = pairs [index ];
840+ rb_hash_aset (set , key , Qtrue );
841+ if (RHASH_SIZE (set ) == before ) {
842+ if (RB_SYMBOL_P (key )) {
843+ return rb_sym2str (key );
844+ }
845+ return key ;
846+ }
847+ }
848+ return Qfalse ;
849+ }
850+
851+ static void emit_duplicate_key_warning (JSON_ParserState * state , VALUE duplicate_key )
852+ {
853+ VALUE message = rb_sprintf (
854+ "detected duplicate key %" PRIsVALUE " in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`" ,
855+ rb_inspect (duplicate_key )
856+ );
857+
858+ emit_parse_warning (RSTRING_PTR (message ), state );
859+ RB_GC_GUARD (message );
860+ }
861+
862+ #ifdef RBIMPL_ATTR_NORETURN
863+ RBIMPL_ATTR_NORETURN ()
864+ #endif
865+ static void raise_duplicate_key_error (JSON_ParserState * state , VALUE duplicate_key )
866+ {
867+ VALUE message = rb_sprintf (
868+ "duplicate key %" PRIsVALUE ,
869+ rb_inspect (duplicate_key )
870+ );
871+
872+ raise_parse_error (RSTRING_PTR (message ), state );
873+ RB_GC_GUARD (message );
874+ }
875+
833876static inline VALUE json_decode_object (JSON_ParserState * state , JSON_ParserConfig * config , size_t count )
834877{
835878 size_t entries_count = count / 2 ;
836879 VALUE object = rb_hash_new_capa (entries_count );
837- rb_hash_bulk_insert (count , rvalue_stack_peek (state -> stack , count ), object );
880+ const VALUE * pairs = rvalue_stack_peek (state -> stack , count );
881+ rb_hash_bulk_insert (count , pairs , object );
838882
839883 if (RB_UNLIKELY (RHASH_SIZE (object ) < entries_count )) {
840884 switch (config -> on_duplicate_key ) {
841885 case JSON_IGNORE :
842886 break ;
843887 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 );
888+ emit_duplicate_key_warning ( state , json_find_duplicated_key ( count , pairs ) );
845889 break ;
846890 case JSON_RAISE :
847- raise_parse_error ( "duplicate key" , state );
891+ raise_duplicate_key_error ( state , json_find_duplicated_key ( count , pairs ) );
848892 break ;
849893 }
850894 }
0 commit comments