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 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'); +