diff options
author | Tony Cook <tony@develop-help.com> | 2016-10-25 16:17:18 +1100 |
---|---|---|
committer | Tony Cook <tony@develop-help.com> | 2016-12-07 15:49:43 +1100 |
commit | 6de2dd46140d0d3ab6813e26940d7b74418b0260 (patch) | |
tree | af1775c49d0bd52c32b705a8f78f6ad4d066b388 /dist/IO | |
parent | eaed4a85bcd00374e80ef8f30b39495d0434407f (diff) | |
download | perl-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.pm | 2 | ||||
-rw-r--r-- | dist/IO/IO.xs | 3 | ||||
-rw-r--r-- | dist/IO/t/io_leak.t | 37 |
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}); +} |