diff options
author | Zefram <zefram@fysh.org> | 2017-12-12 09:47:41 +0000 |
---|---|---|
committer | Zefram <zefram@fysh.org> | 2017-12-12 09:53:32 +0000 |
commit | 16ada235c332e017667585e1a5a00ce43a31c529 (patch) | |
tree | 746383a2364185484906fefefa457d8879b7f84c /pp_sort.c | |
parent | 6cc23b5aabb7c0128c3c2bff71584f07f965efb4 (diff) | |
download | perl-16ada235c332e017667585e1a5a00ce43a31c529.tar.gz |
fix GvSV refcounting in sort
Where a sort operation passes the comparands to a comparison block in $a
and $b, it wasn't taking account of the fact that the GvSV slots in *a
and *b are refcounted. It would write the comparands into those slots
without altering any reference counts, and end by restoring the values
those slots had to start with. This was all fine so long as nothing
else touched those slots during the process. But code running during
the comparison is free to write to them by "*a = \1", which does frob
the reference counts.
Fix it by switching sort to manipulate GvSV in a refcount-preserving
manner, compatible with all other operations on those slots. Fixes
[perl #92264].
Diffstat (limited to 'pp_sort.c')
-rw-r--r-- | pp_sort.c | 15 |
1 files changed, 11 insertions, 4 deletions
@@ -981,8 +981,10 @@ PP(pp_sort) /* we don't want modifications localized */ GvINTRO_off(PL_firstgv); GvINTRO_off(PL_secondgv); - SAVESPTR(GvSV(PL_firstgv)); - SAVESPTR(GvSV(PL_secondgv)); + SAVEGENERICSV(GvSV(PL_firstgv)); + SvREFCNT_inc(GvSV(PL_firstgv)); + SAVEGENERICSV(GvSV(PL_secondgv)); + SvREFCNT_inc(GvSV(PL_secondgv)); } gimme = G_SCALAR; @@ -1118,11 +1120,16 @@ S_sortcv(pTHX_ SV *const a, SV *const b) I32 result; PMOP * const pm = PL_curpm; COP * const cop = PL_curcop; + SV *olda, *oldb; PERL_ARGS_ASSERT_SORTCV; - GvSV(PL_firstgv) = a; - GvSV(PL_secondgv) = b; + olda = GvSV(PL_firstgv); + GvSV(PL_firstgv) = SvREFCNT_inc_simple_NN(a); + SvREFCNT_dec(olda); + oldb = GvSV(PL_secondgv); + GvSV(PL_secondgv) = SvREFCNT_inc_simple_NN(b); + SvREFCNT_dec(oldb); PL_stack_sp = PL_stack_base; PL_op = PL_sortcop; CALLRUNOPS(aTHX); |