@@ -1457,18 +1457,21 @@ static void json_ensure_eof(JSON_ParserState *state)
14571457
14581458static VALUE convert_encoding (VALUE source )
14591459{
1460- int encindex = RB_ENCODING_GET (source );
1460+ StringValue (source );
1461+ int encindex = RB_ENCODING_GET (source );
14611462
1462- if (RB_LIKELY (encindex == utf8_encindex )) {
1463- return source ;
1464- }
1463+ if (RB_LIKELY (encindex == utf8_encindex )) {
1464+ return source ;
1465+ }
14651466
1466- if (encindex == binary_encindex ) {
1467- // For historical reason, we silently reinterpret binary strings as UTF-8
1468- return rb_enc_associate_index (rb_str_dup (source ), utf8_encindex );
1469- }
1467+ if (encindex == binary_encindex ) {
1468+ // For historical reason, we silently reinterpret binary strings as UTF-8
1469+ return rb_enc_associate_index (rb_str_dup (source ), utf8_encindex );
1470+ }
14701471
1471- return rb_funcall (source , i_encode , 1 , Encoding_UTF_8 );
1472+ source = rb_funcall (source , i_encode , 1 , Encoding_UTF_8 );
1473+ StringValue (source );
1474+ return source ;
14721475}
14731476
14741477struct parser_config_init_args {
@@ -1583,10 +1586,16 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
15831586 return self ;
15841587}
15851588
1586- static VALUE cParser_parse (JSON_ParserConfig * config , VALUE Vsource )
1589+ static VALUE cParser_parse (JSON_ParserConfig * config , VALUE src )
15871590{
1588- Vsource = convert_encoding (StringValue (Vsource ));
1589- StringValue (Vsource );
1591+ VALUE Vsource = convert_encoding (src );
1592+
1593+ // Ensure the string isn't mutated under us.
1594+ // The classic API to use is `rb_str_locktmp`, but then we'd
1595+ // need to use `rb_protect` to make sure we always unlock.
1596+ if (Vsource == src ) {
1597+ Vsource = rb_str_new_frozen (Vsource );
1598+ }
15901599
15911600 VALUE rvalue_stack_buffer [RVALUE_STACK_INITIAL_CAPA ];
15921601 rvalue_stack stack = {
@@ -1597,6 +1606,7 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
15971606
15981607 long len ;
15991608 const char * start ;
1609+
16001610 RSTRING_GETMEM (Vsource , start , len );
16011611
16021612 VALUE stack_handle = 0 ;
@@ -1615,6 +1625,7 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
16151625 // it won't cause a leak.
16161626 rvalue_stack_eagerly_release (stack_handle );
16171627 RB_GC_GUARD (stack_handle );
1628+ RB_GC_GUARD (Vsource );
16181629 json_ensure_eof (state );
16191630
16201631 return result ;
@@ -1635,9 +1646,6 @@ static VALUE cParserConfig_parse(VALUE self, VALUE Vsource)
16351646
16361647static VALUE cParser_m_parse (VALUE klass , VALUE Vsource , VALUE opts )
16371648{
1638- Vsource = convert_encoding (StringValue (Vsource ));
1639- StringValue (Vsource );
1640-
16411649 JSON_ParserConfig _config = {0 };
16421650 JSON_ParserConfig * config = & _config ;
16431651 parser_config_init (config , opts , false);
0 commit comments