summaryrefslogtreecommitdiff
path: root/dist/IO
diff options
context:
space:
mode:
authorTony Cook <tony@develop-help.com>2016-10-25 16:17:18 +1100
committerTony Cook <tony@develop-help.com>2016-12-07 15:49:43 +1100
commit6de2dd46140d0d3ab6813e26940d7b74418b0260 (patch)
treeaf1775c49d0bd52c32b705a8f78f6ad4d066b388 /dist/IO
parenteaed4a85bcd00374e80ef8f30b39495d0434407f (diff)
downloadperl-6de2dd46140d0d3ab6813e26940d7b74418b0260.tar.gz
(perl #129788) IO::Poll: fix memory leak
Whenever a magical/tied scalar which dies upon read was passed to _poll() temporary buffer for events was not freed. Adapted from a patch by Sergey Aleynikov <sergey.aleynikov@gmail.com>
Diffstat (limited to 'dist/IO')
-rw-r--r--dist/IO/IO.pm2
-rw-r--r--dist/IO/IO.xs3
-rw-r--r--dist/IO/t/io_leak.t37
3 files changed, 39 insertions, 3 deletions
diff --git a/dist/IO/IO.pm b/dist/IO/IO.pm
index 07a5e51cf3..a9a585269b 100644
--- a/dist/IO/IO.pm
+++ b/dist/IO/IO.pm
@@ -7,7 +7,7 @@ use Carp;
use strict;
use warnings;
-our $VERSION = "1.37";
+our $VERSION = "1.38";
XSLoader::load 'IO', $VERSION;
sub import {
diff --git a/dist/IO/IO.xs b/dist/IO/IO.xs
index fe749a63e6..15ef9b2aee 100644
--- a/dist/IO/IO.xs
+++ b/dist/IO/IO.xs
@@ -318,7 +318,7 @@ PPCODE:
{
#ifdef HAS_POLL
const int nfd = (items - 1) / 2;
- SV *tmpsv = NEWSV(999,nfd * sizeof(struct pollfd));
+ SV *tmpsv = sv_2mortal(NEWSV(999,nfd * sizeof(struct pollfd)));
/* We should pass _some_ valid pointer even if nfd is zero, but it
* doesn't matter what it is, since we're telling it to not check any fds.
*/
@@ -337,7 +337,6 @@ PPCODE:
sv_setiv(ST(i), fds[j].revents); i++;
}
}
- SvREFCNT_dec(tmpsv);
XSRETURN_IV(ret);
#else
not_here("IO::Poll::poll");
diff --git a/dist/IO/t/io_leak.t b/dist/IO/t/io_leak.t
new file mode 100644
index 0000000000..08cbe2b884
--- /dev/null
+++ b/dist/IO/t/io_leak.t
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+use Test::More;
+
+eval { require XS::APItest; XS::APItest->import('sv_count'); 1 }
+ or plan skip_all => "No XS::APItest::sv_count() available";
+
+plan tests => 1;
+
+sub leak {
+ my ($n, $delta, $code, $name) = @_;
+ my $sv0 = 0;
+ my $sv1 = 0;
+ for my $i (1..$n) {
+ &$code();
+ $sv1 = sv_count();
+ $sv0 = $sv1 if $i == 1;
+ }
+ cmp_ok($sv1-$sv0, '<=', ($n-1)*$delta, $name);
+}
+
+# [perl #129788] IO::Poll shouldn't leak on errors
+{
+ package io_poll_leak;
+ use IO::Poll;
+
+ sub TIESCALAR { bless {} }
+ sub FETCH { die }
+
+ tie(my $a, __PACKAGE__);
+ sub f {eval { IO::Poll::_poll(0, $a, 1) }}
+
+ ::leak(5, 0, \&f, q{IO::Poll::_poll shouldn't leak});
+}