|
|
42e3bba |
From d531a72eb4a6ecbc65b213f4704f4b197f6730ff Mon Sep 17 00:00:00 2001
|
|
|
42e3bba |
From: David Mitchell <davem@iabyn.com>
|
|
|
42e3bba |
Date: Tue, 26 Mar 2019 11:04:07 +0000
|
|
|
42e3bba |
Subject: [PATCH] avoid leak with local $h{foo}, $a[n]
|
|
|
42e3bba |
MIME-Version: 1.0
|
|
|
42e3bba |
Content-Type: text/plain; charset=UTF-8
|
|
|
42e3bba |
Content-Transfer-Encoding: 8bit
|
|
|
42e3bba |
|
|
|
42e3bba |
When SAVEt_DELETE / SAVEt_ADELETE deletes a hash/array entry on scope
|
|
|
42e3bba |
exit, they also decrement the refcount of the hash/array, and for the
|
|
|
42e3bba |
hash, also free the saved key.
|
|
|
42e3bba |
|
|
|
42e3bba |
However, if the call to hv_delete() or av_delete() dies (e.g. when
|
|
|
42e3bba |
calling a tied DELETE method) then the hash/array and key will leak
|
|
|
42e3bba |
because leave_scope() calls av/hv_delete(), *then* does the
|
|
|
42e3bba |
SvREFCNT_dec() etc.
|
|
|
42e3bba |
|
|
|
42e3bba |
The fix is to push new FREEPV/FREESV actions just before calling
|
|
|
42e3bba |
av/hv_delete().
|
|
|
42e3bba |
|
|
|
42e3bba |
Petr Písař: Ported to 5.26.3 from
|
|
|
42e3bba |
85df897fcfe76250deecfdeb239ba1e4279d8532.
|
|
|
42e3bba |
|
|
|
42e3bba |
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
|
|
42e3bba |
---
|
|
|
42e3bba |
scope.c | 17 ++++++++++++++---
|
|
|
42e3bba |
t/op/tie.t | 37 +++++++++++++++++++++++++++++++++++++
|
|
|
42e3bba |
2 files changed, 51 insertions(+), 3 deletions(-)
|
|
|
42e3bba |
|
|
|
42e3bba |
diff --git a/scope.c b/scope.c
|
|
|
42e3bba |
index a7c17e8..e054137 100644
|
|
|
42e3bba |
--- a/scope.c
|
|
|
42e3bba |
+++ b/scope.c
|
|
|
42e3bba |
@@ -1245,15 +1245,26 @@ Perl_leave_scope(pTHX_ I32 base)
|
|
|
42e3bba |
|
|
|
42e3bba |
case SAVEt_DELETE:
|
|
|
42e3bba |
a0 = ap[0]; a1 = ap[1]; a2 = ap[2];
|
|
|
42e3bba |
+ /* hv_delete could die, so free the key and SvREFCNT_dec the
|
|
|
42e3bba |
+ * hv by pushing new save actions
|
|
|
42e3bba |
+ */
|
|
|
42e3bba |
+ /* ap[0] is the key */
|
|
|
42e3bba |
+ ap[1].any_uv = SAVEt_FREEPV; /* was len */
|
|
|
42e3bba |
+ /* ap[2] is the hv */
|
|
|
42e3bba |
+ ap[3].any_uv = SAVEt_FREESV; /* was SAVEt_DELETE */
|
|
|
42e3bba |
+ PL_savestack_ix += 4;
|
|
|
42e3bba |
(void)hv_delete(a2.any_hv, a0.any_pv, a1.any_i32, G_DISCARD);
|
|
|
42e3bba |
- SvREFCNT_dec(a2.any_hv);
|
|
|
42e3bba |
- Safefree(a0.any_ptr);
|
|
|
42e3bba |
break;
|
|
|
42e3bba |
|
|
|
42e3bba |
case SAVEt_ADELETE:
|
|
|
42e3bba |
a0 = ap[0]; a1 = ap[1];
|
|
|
42e3bba |
+ /* av_delete could die, so SvREFCNT_dec the av by pushing a
|
|
|
42e3bba |
+ * new save action
|
|
|
42e3bba |
+ */
|
|
|
42e3bba |
+ ap[0].any_av = a1.any_av;
|
|
|
42e3bba |
+ ap[1].any_uv = SAVEt_FREESV;
|
|
|
42e3bba |
+ PL_savestack_ix += 2;
|
|
|
42e3bba |
(void)av_delete(a1.any_av, a0.any_iv, G_DISCARD);
|
|
|
42e3bba |
- SvREFCNT_dec(a1.any_av);
|
|
|
42e3bba |
break;
|
|
|
42e3bba |
|
|
|
42e3bba |
case SAVEt_DESTRUCTOR_X:
|
|
|
42e3bba |
diff --git a/t/op/tie.t b/t/op/tie.t
|
|
|
42e3bba |
index 12fc935..48c79ca 100644
|
|
|
42e3bba |
--- a/t/op/tie.t
|
|
|
42e3bba |
+++ b/t/op/tie.t
|
|
|
42e3bba |
@@ -1517,3 +1517,40 @@ print "$h{x}\n";
|
|
|
42e3bba |
EXPECT
|
|
|
42e3bba |
foo
|
|
|
42e3bba |
bar
|
|
|
42e3bba |
+########
|
|
|
42e3bba |
+# dying while doing a SAVEt_DELETE dureing scope exit leaked a copy of the
|
|
|
42e3bba |
+# key. Give ASan something to play with
|
|
|
42e3bba |
+sub TIEHASH { bless({}, $_[0]) }
|
|
|
42e3bba |
+sub EXISTS { 0 }
|
|
|
42e3bba |
+sub DELETE { die; }
|
|
|
42e3bba |
+sub DESTROY { print "destroy\n"; }
|
|
|
42e3bba |
+
|
|
|
42e3bba |
+eval {
|
|
|
42e3bba |
+ my %h;
|
|
|
42e3bba |
+ tie %h, "main";
|
|
|
42e3bba |
+ local $h{foo};
|
|
|
42e3bba |
+ print "leaving\n";
|
|
|
42e3bba |
+};
|
|
|
42e3bba |
+print "left\n";
|
|
|
42e3bba |
+EXPECT
|
|
|
42e3bba |
+leaving
|
|
|
42e3bba |
+destroy
|
|
|
42e3bba |
+left
|
|
|
42e3bba |
+########
|
|
|
42e3bba |
+# ditto for SAVEt_DELETE with an array
|
|
|
42e3bba |
+sub TIEARRAY { bless({}, $_[0]) }
|
|
|
42e3bba |
+sub EXISTS { 0 }
|
|
|
42e3bba |
+sub DELETE { die; }
|
|
|
42e3bba |
+sub DESTROY { print "destroy\n"; }
|
|
|
42e3bba |
+
|
|
|
42e3bba |
+eval {
|
|
|
42e3bba |
+ my @a;
|
|
|
42e3bba |
+ tie @a, "main";
|
|
|
42e3bba |
+ delete local $a[0];
|
|
|
42e3bba |
+ print "leaving\n";
|
|
|
42e3bba |
+};
|
|
|
42e3bba |
+print "left\n";
|
|
|
42e3bba |
+EXPECT
|
|
|
42e3bba |
+leaving
|
|
|
42e3bba |
+destroy
|
|
|
42e3bba |
+left
|
|
|
42e3bba |
--
|
|
|
42e3bba |
2.20.1
|
|
|
42e3bba |
|