From df0825b26d3c8002f130acbacc65836066c616dd Mon Sep 17 00:00:00 2001 From: Lukas Mai Date: Fri, 29 Aug 2025 05:33:32 +0200 Subject: [PATCH 1/2] add another email alias for Richard Leach --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 3d04b068e983..b2e5ccf2f8c9 100644 --- a/.mailmap +++ b/.mailmap @@ -750,6 +750,7 @@ Richard Foley Richard Foley Richard L. Maus, Jr. Richard L. Maus Richard Leach Richard Leach +Richard Leach richardleach Richard Soderberg Richard Soderberg Richard Soderberg From 46b447d1ea02d67dbff9aa7de926b9d0ba77c696 Mon Sep 17 00:00:00 2001 From: Richard Leach Date: Fri, 29 Aug 2025 00:39:57 +0100 Subject: [PATCH 2/2] Perl_newSVsv_flags_NN_PVxx: do not copy the SVprv_WEAKREF flag When copying source SV flags to the new destination SV, this function failed to account for SVprv_WEAKREF and SVf_IVisUV flags having the same numerical value - 0x80000000. The SVprv_WEAKREF flag was consequently erroneously propagated when copying weakened references. This didn't trip existing tests because SVt_IVs (the predominant SV type for RVs) are copied using different code paths. This commit: * Always drops the SVprv_WEAKREF flag in the affected code path * Adds additional tests for copying weakened SVs --- sv.c | 4 ++++ t/op/svflags.t | 32 +++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/sv.c b/sv.c index 40bfcc78761c..087626319596 100644 --- a/sv.c +++ b/sv.c @@ -5046,6 +5046,10 @@ S_newSVsv_flags_NN_PVxx(pTHX_ SV* dsv, SV* ssv, const I32 flags) SvNV_set(dsv, SvNVX(ssv)); break; case SVf_ROK: /* [ 3% ]*/ + /* Another corner case here. SVf_IVisUV and SVprv_WEAKREF + * have the same underlying value. We do not want to + * propagate the latter. */ + SvFLAGS(dsv) &= ~SVprv_WEAKREF; SvRV_set(dsv, SvREFCNT_inc(SvRV(ssv))); return dsv; default: /* [ 2% ]*/ diff --git a/t/op/svflags.t b/t/op/svflags.t index 433919504a5b..e708979f6095 100644 --- a/t/op/svflags.t +++ b/t/op/svflags.t @@ -10,7 +10,7 @@ BEGIN { # Tests the new documented mechanism for determining the original type # of an SV. -plan tests => 16; +plan tests => 22; use strict; use B qw(svref_2object SVf_IOK SVf_NOK SVf_POK); @@ -83,3 +83,33 @@ is($xobj->FLAGS & (SVf_IOK | SVf_POK), SVf_POK, "correct base flags on PV"); $y = $x + 10; is($xobj->FLAGS & (SVf_IOK | SVf_POK), (SVf_IOK | SVf_POK), "POK still set on PV used as number"); + + +# GH #23637, GH #23646 - newSVsv_flags_NN erroneously copied WEAKREF in *some* code paths + +my $ref = []; +my ($wref, $cref); + +# Weakened reference SV is an SVt_IV +$wref = $ref; +builtin::weaken($wref); +ok(builtin::is_weak($wref), 'a weakened SVt_IV ref has WEAKREF set'); +$cref = [ $wref ]; +ok(!builtin::is_weak( $cref->[0] ), 'SVt_IV copies do NOT have WEAKREF set'); + +# Weakened reference SV is an SVt_PV +$wref = 'blip'; +$wref = $ref; +builtin::weaken($wref); +ok(builtin::is_weak($wref), 'a weakened SVt_PV ref has WEAKREF set'); +$cref = [ $wref ]; +ok(!builtin::is_weak( $cref->[0] ), 'SVt_PV copies do NOT have WEAKREF set'); + +# Weakened reference SV is an SVt_PVIV +$wref = 1; +$wref = $ref; +builtin::weaken($wref); +ok(builtin::is_weak($wref), 'a weakened SVt_PVIV ref has WEAKREF set'); +$cref = [ $wref ]; +ok(!builtin::is_weak( $cref->[0] ), 'SVt_PVIV copies do NOT have WEAKREF set'); +