Skip Menu |

This queue is for tickets about the Image-Size CPAN distribution.

Report information
The Basics
Id: 20623
Status: resolved
Priority: 0/
Queue: Image-Size

People
Owner: Nobody in particular
Requestors: aver [...] pvk.org.ru
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in:
  • 2.992
  • 3.0
Fixed in: 3.0



Subject: "substr outside of string" under persistent environment
Use of Image::Size under persistent environment (e.g. mod_perl) causes error "substr outside of string at blib/lib/Image/Size.pm (autosplit into blib/lib/auto/Image/Size/swfmxsize.al) line 1135." This bug can be reproduced by running next command on many CWS files: imgsize /dir/with/many/CWS/files/*.swf But while all files processed separately - everything is ok (but slow): ls -1 /dir/with/many/CWS/files/*.swf | xargs -n1 imgsize Attached patch solves this problem. Details: $ uname -mrs FreeBSD 6.1-PRERELEASE i386 $ perl -v This is perl, v5.8.8 built for i386-freebsd-64int and $ uname -mrs Linux 2.6.16c3-reiser4 i686 $ perl -v This is perl, v5.8.4 built for i386-linux-thread-multi $ perl -MImage::Size -e 'print $Image::Size::VERSION' 3.0
Subject: Image-Size-3.0-swfmx.patch
--- /usr/local/lib/perl5/site_perl/5.8.8/Image/Size.pm.orig Fri Jul 21 19:16:39 2006 +++ /usr/local/lib/perl5/site_perl/5.8.8/Image/Size.pm Fri Jul 21 23:27:22 2006 @@ -1128,7 +1128,9 @@ my $ver = _bin2int(unpack 'B8', substr($header, 3, 1)); my ($d, $status) = Compress::Zlib::inflateInit(); - $header = $d->inflate(substr($header, 8, 1024)); + my $buffer = substr($header, 8, 1024); + ($header, $status) = $d->inflate($buffer); + return (undef, undef, 'SWC') unless $status == Z_OK or $status == Z_STREAM_END; my $bs = unpack 'B133', substr($header, 0, 9); my $bits = _bin2int(substr($bs, 0, 5));
From: gerryster [...] gmail.com
The problem can be reproduced by issuing a second call to imgzise with a compressed (CWS) file. The "under persistent environment" part of this bug can be explained by this fact. Attached is a patch to t/all.t which demonstrates this problem. Note, I disabled caching because the problem code is never executed for files when caching is set. To get around the problem in my environment I created my own version of sub swfmxsize. Here is my version: # adapted from Image::Size::my_swfmxsize() to work in isolation and solve # bug: http://rt.cpan.org/Public/Bug/Display.html?id=20623 sub _my_swfmxsize { my ($image) = @_; my $header = substr($$image, 0, 1058); my $ver = Image::Size::_bin2int(unpack 'B8', substr($header, 3, 1)); my ($d, $status) = Compress::Zlib::inflateInit(); my $buffer = substr($header, 8, 1024); # cannot pass substr to inflate!!! ($header, $status) = $d->inflate($buffer); # we know this is a CWS, but zlib had a problem if ($status != Z_OK && $status != Z_STREAM_END) { return (undef, undef, 'Corrupt CWS, unable to decompress header: ' . $d->msg()) } my $bs = unpack 'B133', substr($header, 0, 9); my $bits = Image::Size::_bin2int(substr($bs, 0, 5)); my $x = int(Image::Size::_bin2int(substr($bs, 5+$bits, $bits))/20); my $y = int(Image::Size::_bin2int(substr($bs, 5+$bits*3, $bits))/20); return ($x, $y, 'CWS'); } Note that this version does not pass the substr call directly to d->inflate. This line causes the error: substr outside of string at blib/lib/Image/Size.pm (autosplit into blib/lib/auto/Image/Size/swfmxsize.al) line 1135. Reading the substring perldoc page it says towards the end: If the lvalue returned by substr is used after the EXPR is changed in any way, the behaviour may not be as expected and is subject to change. This caveat includes code such as "print(substr($foo,$a,$b)=$bar)" or "(sub- str($foo,$a,$b)=$bar)=$fud" (where $foo is changed via the sub- string assignment, and then the substr is used again), or where a substr() is aliased via a "foreach" loop or passed as a parameter or a reference to it is taken and then the alias, parameter, or deref'd reference either is used after the origi- nal EXPR has been changed or is assigned to and then used a second time. So in this case since substr is being passed to a method it is being used as an lvalue since arguments are passed into subroutines by aliasing. Since the behavior is unexpected your Perl version/OS combination may produce different results. I am using Perl " v5.8.5 built for i686-linux".
7c7 < use Test::More tests => 17; --- > use Test::More tests => 20; 58,59c58,66 < ($x, $y, $id) = imgsize("${dir}8.swf"); < ok(($x == 280 && $y == 140 && $id eq 'CWS'), 'Basic CWS format test'); --- > # Tests two consecutive calls, first with cache on then with cache off > for(1..2) { > for(1..2) { > ($x, $y, $id) = imgsize("${dir}8.swf"); > ok(($x == 280 && $y == 140 && $id eq 'CWS'), > 'Basic CWS format test, $NO_CACH = ' . $NO_CACHE); > } > $NO_CACHE=1; > }
From: gerryster [...] gmail.com
The problem can be reproduced by issuing a second call to imgsize with a compressed (CWS) file. The "under persistent environment" part of this bug can be explained by this fact. Attached is a patch to t/all.t which demonstrates this problem. Note, I disabled caching because the problem code is never executed for files when caching is set. To get around the problem in my environment I created my own version of sub swfmxsize. Here is my version: # adapted from Image::Size::my_swfmxsize() to work in isolation and solve # bug: http://rt.cpan.org/Public/Bug/Display.html?id=20623 sub _my_swfmxsize { my ($image) = @_; my $header = substr($$image, 0, 1058); my $ver = Image::Size::_bin2int(unpack 'B8', substr($header, 3, 1)); my ($d, $status) = Compress::Zlib::inflateInit(); my $buffer = substr($header, 8, 1024); # cannot pass substr to inflate!!! ($header, $status) = $d->inflate($buffer); # we know this is a CWS, but zlib had a problem if ($status != Z_OK && $status != Z_STREAM_END) { return (undef, undef, 'Corrupt CWS, unable to decompress header: ' . $d->msg()) } my $bs = unpack 'B133', substr($header, 0, 9); my $bits = Image::Size::_bin2int(substr($bs, 0, 5)); my $x = int(Image::Size::_bin2int(substr($bs, 5+$bits, $bits))/20); my $y = int(Image::Size::_bin2int(substr($bs, 5+$bits*3, $bits))/20); return ($x, $y, 'CWS'); } Note that this version does not pass the substr call directly to d->inflate(). This line causes the error: substr outside of string at blib/lib/Image/Size.pm (autosplit into blib/lib/auto/Image/Size/swfmxsize.al) line 1135. Toward the end of the substr perldoc page it states: If the lvalue returned by substr is used after the EXPR is changed in any way, the behaviour may not be as expected and is subject to change. This caveat includes code such as "print(substr($foo,$a,$b)=$bar)" or "(sub- str($foo,$a,$b)=$bar)=$fud" (where $foo is changed via the sub- string assignment, and then the substr is used again), or where a substr() is aliased via a "foreach" loop or passed as a parameter or a reference to it is taken and then the alias, parameter, or deref'd reference either is used after the origi- nal EXPR has been changed or is assigned to and then used a second time. So in this case since substr is being passed to a method it is being used as an lvalue since arguments are passed into subroutines by aliasing. Since the behavior is unexpected your Perl version/OS combination may produce different results. I am using Perl " v5.8.5 built for i686-linux". Also, to illustrate the sub string issue in a more controlled environment try running: perl -e'sub problem{}; problem(substr("asdf",5,6))' On my system this dies (has a return code of 255) with the message "substr outside of string at -e line 1." When I run this on a different Perl (version 5.005_03 built for sun4-solaris) I get the same message but only as a warning (Perl returns with a 0). Also the die or warning only occurs when the offset is outside the bounds of the string. This example executes cleanly: perl -e'sub problem{}; problem(substr("asdf",4,5))' And to demonstrate the point about the problem occurring only in the context of a subroutine call, this also executes cleanly: perl -e'substr("asdf",5,6)' I hope this helps!
7c7 < use Test::More tests => 17; --- > use Test::More tests => 20; 58,59c58,66 < ($x, $y, $id) = imgsize("${dir}8.swf"); < ok(($x == 280 && $y == 140 && $id eq 'CWS'), 'Basic CWS format test'); --- > # Tests two consecutive calls, first with cache on then with cache off > for(1..2) { > for(1..2) { > ($x, $y, $id) = imgsize("${dir}8.swf"); > ok(($x == 280 && $y == 140 && $id eq 'CWS'), > 'Basic CWS format test, $NO_CACH = ' . $NO_CACHE); > } > $NO_CACHE=1; > }
From: gerryster [...] gmail.com
Oops! Sorry about the double post, the bottom one is the complete one!
This was fixed in 3.1, forgot to close the ticket.