@@ -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,61 @@ 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+ return key ;
843+ }
844+ }
845+ return Qfalse ;
846+ }
847+
848+ static void emit_duplicate_key_warning (JSON_ParserState * state , VALUE duplicate_key )
849+ {
850+ VALUE message = rb_sprintf (
851+ "detected duplicate key \"%s\" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`" ,
852+ RSTRING_PTR (duplicate_key )
853+ );
854+
855+ emit_parse_warning (RSTRING_PTR (message ), state );
856+ RB_GC_GUARD (message );
857+ }
858+
859+ #ifdef RBIMPL_ATTR_NORETURN
860+ RBIMPL_ATTR_NORETURN ()
861+ #endif
862+ static void raise_duplicate_key_error (JSON_ParserState * state , VALUE duplicate_key )
863+ {
864+ VALUE message = rb_sprintf (
865+ "duplicate key \"%s\"" ,
866+ RSTRING_PTR (duplicate_key )
867+ );
868+
869+ raise_parse_error (RSTRING_PTR (message ), state );
870+ RB_GC_GUARD (message );
871+ }
872+
833873static inline VALUE json_decode_object (JSON_ParserState * state , JSON_ParserConfig * config , size_t count )
834874{
835875 size_t entries_count = count / 2 ;
836876 VALUE object = rb_hash_new_capa (entries_count );
837- rb_hash_bulk_insert (count , rvalue_stack_peek (state -> stack , count ), object );
877+ const VALUE * pairs = rvalue_stack_peek (state -> stack , count );
878+ rb_hash_bulk_insert (count , pairs , object );
838879
839880 if (RB_UNLIKELY (RHASH_SIZE (object ) < entries_count )) {
840881 switch (config -> on_duplicate_key ) {
841882 case JSON_IGNORE :
842883 break ;
843884 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 );
885+ emit_duplicate_key_warning ( state , json_find_duplicated_key ( count , pairs ) );
845886 break ;
846887 case JSON_RAISE :
847- raise_parse_error ( "duplicate key" , state );
888+ raise_duplicate_key_error ( state , json_find_duplicated_key ( count , pairs ) );
848889 break ;
849890 }
850891 }
0 commit comments