Commit bc3f154993 for perl
commit bc3f1549931f2e6d028dca4bdc9a9001496a7f51
Author: Alin Iacob <alinbsp@gmail.com>
Date: Fri Oct 2 23:30:59 2026 +0300
sv.c: handle static strings in PERL_NO_COW builds
The no-COW paths in sv_uncow() and sv_clear() treated static strings
as shared hash keys. Boolean values use static strings even with
PERL_NO_COW, so modifying or freeing them could crash.
Only call unshare_hek() for shared hash keys.
Fixes #19987
diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 450725232d..f96be57d24 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -436,6 +436,11 @@ XXX
=item *
+Builds with C<PERL_NO_COW> could crash when modifying or freeing boolean
+values. This has been fixed. [GH #19987]
+
+=item *
+
C<goto> within a defer block should now work more consistently. [GH #19240]
=back
diff --git a/sv.c b/sv.c
index b8ae412b72..7f960c47c0 100644
--- a/sv.c
+++ b/sv.c
@@ -6064,6 +6064,7 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags)
#else
const char * const pvx = SvPVX_const(sv);
const STRLEN len = SvCUR(sv);
+ const bool was_shared_hek = SvIsCOW_shared_hash(sv);
SvIsCOW_off(sv);
SvPV_set(sv, NULL);
SvLEN_set(sv, 0);
@@ -6075,7 +6076,8 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags)
Move(pvx,SvPVX(sv),len,char);
*SvEND(sv) = '\0';
}
- unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
+ if (was_shared_hek)
+ unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
#endif
}
}
@@ -8170,7 +8172,7 @@ Perl_sv_clear(pTHX_ SV *const orig_sv)
&& !(SvTYPE(sv) == SVt_PVIO
&& !(IoFLAGS(sv) & IOf_FAKE_DIRP)))
Safefree(SvPVX_mutable(sv));
- else if (SvPVX_const(sv) && SvIsCOW(sv)) {
+ else if (SvPVX_const(sv) && SvIsCOW_shared_hash(sv)) {
unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
}
#endif