diff options
author | Father Chrysostomos <sprout@cpan.org> | 2013-06-07 08:26:03 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2013-06-07 08:26:40 -0700 |
commit | 9332b95f7fd17b2400da85452a406bc151d30d91 (patch) | |
tree | 7b4f1875a9a35c6afb583bcd778e74061293a8b5 /pp.c | |
parent | e987ad1c31f774bda2a3a14929ae1fc88f759ccc (diff) | |
download | perl-9332b95f7fd17b2400da85452a406bc151d30d91.tar.gz |
Stop delete local $ENV{foo} from leaking
It was only leaking when the env var did not already exist.
The code in question in pp.c:S_do_delete_local was calling hv_delete
to delete the element, which autovivifies, deletes, and returns a mag-
ical mortal for magical hashes. It was assuming that if a value was
returned the element must have existed, so it was calling SvREFCNT_inc
on the returned mortal to de-mortalize it (since it has to be
restored). Whether the element had existed previously was already
recorded in a bool named ‘preeminent’ (strange name). This variable
should be checked before the SvREFCNT_inc.
I found the same bug in the array code path, potentially affecting
@- and @+, so I fixed it. But I didn’t write a test, as that would
involve a custom regexp engine.
Diffstat (limited to 'pp.c')
-rw-r--r-- | pp.c | 6 |
1 files changed, 4 insertions, 2 deletions
@@ -4511,7 +4511,8 @@ S_do_delete_local(pTHX) } else { sv = hv_delete_ent(hv, keysv, 0, 0); - SvREFCNT_inc_simple_void(sv); /* De-mortalize */ + if (preeminent) + SvREFCNT_inc_simple_void(sv); /* De-mortalize */ } if (preeminent) { if (!sv) DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv)); @@ -4546,7 +4547,8 @@ S_do_delete_local(pTHX) } else { sv = av_delete(av, idx, 0); - SvREFCNT_inc_simple_void(sv); /* De-mortalize */ + if (preeminent) + SvREFCNT_inc_simple_void(sv); /* De-mortalize */ } if (preeminent) { save_aelem_flags(av, idx, &sv, SAVEf_KEEPOLDELEM); |