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