diff --git a/doop.c b/doop.c index 89a5e38c5506..c603b5e5c378 100644 --- a/doop.c +++ b/doop.c @@ -662,7 +662,7 @@ Perl_do_join(pTHX_ SV *sv, SV *delim, SV **mark, SV **sp) I32 items = sp - mark; STRLEN len; STRLEN delimlen; - const char * const delims = SvPV_const(delim, delimlen); + const char * delimpv = SvPV_const(delim, delimlen); PERL_ARGS_ASSERT_DO_JOIN; @@ -699,11 +699,20 @@ Perl_do_join(pTHX_ SV *sv, SV *delim, SV **mark, SV **sp) } if (delimlen) { + bool delim_copied = false; const U32 delimflag = DO_UTF8(delim) ? SV_CATUTF8 : SV_CATBYTES; for (; items > 0; items--,mark++) { STRLEN len; const char *s; - sv_catpvn_flags(sv,delims,delimlen,delimflag); + if(*mark == delim && !delim_copied) { + /* Take a copy in case delim SV is a tied SV with a + * self-modifying FETCH [GH #21458] + */ + delimpv = savepvn(delimpv, delimlen); + SAVEFREEPV(delimpv); + delim_copied = true; + } + sv_catpvn_flags(sv,delimpv,delimlen,delimflag); s = SvPV_const(*mark,len); sv_catpvn_flags(sv,s,len, DO_UTF8(*mark) ? SV_CATUTF8 : SV_CATBYTES);