Skip Menu |

This queue is for tickets about the IO-stringy CPAN distribution.

Report information
The Basics
Id: 33274
Status: new
Priority: 0/
Queue: IO-stringy

People
Owner: Nobody in particular
Requestors: ianburrell [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 2.110
Fixed in: (no value)



Subject: IO::Scalar read with offset beyond buffer does not extend string
The perlfunc docs describe the read function as padding the buffer with '\0' when the offset is beyond the end of the string. substr produces an error instead of extending the string. This test: $M = "READ/OFFSET10: reading to offset appends data"; $GH->seek(0, 0); $GH->read($BUF); $GH->read($BUF, 10, 10); warn $BUF; $T->ok(($BUF eq "A diner while dining"), $M); fails with: substr outside of string at lib/IO/Scalar.pm line 457. I think the padding can be accomplished with: if (length($_[1]) < $off) { $_[1] .= ('\0' x ($off + 1 - length($_[1]))); }
From: ianburrell [...] gmail.com
Here is a patch with a correct test and the fix for both IO::Scalar and IO::ScalaraArray.
diff -r a9b28cae1d0a lib/IO/Scalar.pm --- a/lib/IO/Scalar.pm Thu Feb 14 16:11:16 2008 -0800 +++ b/lib/IO/Scalar.pm Thu Feb 14 16:29:34 2008 -0800 @@ -454,7 +454,16 @@ sub read { my $read = substr(${*$self->{SR}}, *$self->{Pos}, $n); $n = length($read); *$self->{Pos} += $n; - ($off ? substr($_[1], $off) : $_[1]) = $read; + + if ($off) { + if (length($_[1]) < $off) { + $_[1] .= ('\0' x ($off + 1 - length($_[1]))); + } + substr($_[1], $off) = $read; + } else { + $_[1] = $read; + } + return $n; } diff -r a9b28cae1d0a lib/IO/ScalarArray.pm --- a/lib/IO/ScalarArray.pm Thu Feb 14 16:11:16 2008 -0800 +++ b/lib/IO/ScalarArray.pm Thu Feb 14 16:29:34 2008 -0800 @@ -409,7 +409,14 @@ sub read { ### print "getline\n"; my $justread; my $len; - ($off ? substr($_[1], $off) : $_[1]) = ''; + if ($off) { + if (length($_[1]) < $off) { + $_[1] .= ('\0' x ($off + 1 - length($_[1]))); + } + substr($_[1], $off) = ''; + } else { + $_[1] = ''; + } ### Stop when we have zero bytes to go, or when we hit EOF: my @got; diff -r a9b28cae1d0a t/Common.pm --- a/t/Common.pm Thu Feb 14 16:11:16 2008 -0800 +++ b/t/Common.pm Thu Feb 14 16:29:34 2008 -0800 @@ -160,7 +160,7 @@ sub test_getline { # test_read HANDLE #------------------------------ # Test read(). -# 4 +# 5 # sub test_read { my ($self, $GH) = @_; @@ -170,13 +170,19 @@ sub test_read { $GH->seek(0,0); $GH->read($BUF,10); $T->ok(($BUF eq "A diner wh"), $M); - + $M = "READ/NEXT10: reading next 10 bytes with read(10)"; $GH->read($BUF,10); $T->ok(($BUF eq "ile dining"), $M); - + $M = "READ/TELL20: tell() the current location as 20"; $T->ok(($GH->tell == 20), $M); + + $M = "READ/OFFSET10: reading to offset appends data"; + $GH->seek(0, 0); + $GH->read($BUF, 10); + $GH->read($BUF, 10, 10); + $T->ok(($BUF eq "A diner while dining"), $M); $M = "READ/SLURP: seek(0,START) + read(1000) reads in whole handle"; $GH->seek(0,0); diff -r a9b28cae1d0a t/IO_Lines.t --- a/t/IO_Lines.t Thu Feb 14 16:11:16 2008 -0800 +++ b/t/IO_Lines.t Thu Feb 14 16:29:34 2008 -0800 @@ -21,7 +21,7 @@ Common->test_init(TBone=>$T); # Set the counter: my $main_tests = 1; -my $common_tests = (1 + 1 + 4 + 4 + 3 + 4 +my $common_tests = (1 + 1 + 4 + 5 + 3 + 4 + Common->test_recordsep_count($RECORDSEP_TESTS)); $T->begin($main_tests + $common_tests); diff -r a9b28cae1d0a t/IO_Scalar.t --- a/t/IO_Scalar.t Thu Feb 14 16:11:16 2008 -0800 +++ b/t/IO_Scalar.t Thu Feb 14 16:29:34 2008 -0800 @@ -22,7 +22,7 @@ Common->test_init(TBone=>$T); ### Set the counter: my $main_tests = 1 + 1; -my $common_tests = (1 + 1 + 4 + 4 + 3 + 4 +my $common_tests = (1 + 1 + 4 + 5 + 3 + 4 + Common->test_recordsep_count($RECORDSEP_TESTS)); $T->begin($main_tests + $common_tests); diff -r a9b28cae1d0a t/IO_ScalarArray.t --- a/t/IO_ScalarArray.t Thu Feb 14 16:11:16 2008 -0800 +++ b/t/IO_ScalarArray.t Thu Feb 14 16:29:34 2008 -0800 @@ -21,7 +21,7 @@ Common->test_init(TBone=>$T); # Set the counter: my $main_tests = 1; -my $common_tests = (1 + 1 + 4 + 4 + 3 + 4 +my $common_tests = (1 + 1 + 4 + 5 + 3 + 4 + Common->test_recordsep_count($RECORDSEP_TESTS)); $T->begin($main_tests + $common_tests);