Skip to content

IO::Uncompress::Unzip stream can't be read by Storable (PerlIO) - Demo showing how to fix #33

@tlhackque

Description

@tlhackque

I have a small reproducer demonstrating that IO::Uncompress::Unzip's file descriptor won't work with Storable. Presumably there are other cases...

If I had to guess, it would be that the FH, which is passed to Storable's XS code, may not be positioned (for XS) correctly after header detection...Clearly, it works for ordinary Perl consumers.

Here is the sequence:

  • Write a small hash to a file with Storable.
  • Using system zip, create a zip file containing the Storable file.
  • Read the Storable file from \*STDIN & verify that it's what we wrote. (passes)
  • Read the Storable file from *STDIN with IUU, passing the file handle to Storable (fails)
  • Read the zip archive of the Storable file from *STDIN with IUU, passing file handle to Storable (fails)
  • Delete the file, extract it from the Zip archive, and read it from *STDIN with Storable (passes

From this, we can see that the file is written correctly by Storable, and can be read after a trip thru the Zip archive. Further, Storable is happy reading from a file handle.

BUT, neither the raw file nor the Zip member can be read correctly by Storable if IUU is in the middle.

IO::Uncompress::Unzip 2.102

In real life, the work-around is to write all 300MB of uncompressed data to a tempfile, and pass that handle to Storable. Which is suboptimal...

Here is the test program:

#!/usr/bin/perl

use warnings;
use strict;
use Storable( qw/store fd_retrieve/ );
use IO::Uncompress::Unzip;

exit unless( @ARGV);
my $cmd = shift;

if( $cmd eq "write" ) {
    my $file = shift or die( "no file\n" );
    my $hash = { key => 'value' };

    store( $hash, $file );
    system( "zip $file.zip $file" );
    exit;
}
if( $cmd eq "storable" ) {
    binmode( \*STDIN );
    my $read = fd_retrieve( \*STDIN );
    if( !$read || !exists $read->{key} ){
        print "Failed\n";
    } else {
        print "OK\n";
    }
    exit;
}
if( $cmd eq 'uncompress' ) {
    my $in = IO::Uncompress::Unzip->new( \*STDIN, { } ) or die( "IUU\n" );
    binmode( $in );
    my $read = fd_retrieve( $in );
    if( !$read || !exists $read->{key} ){
        print "Failed\n";
    } else {
        print "OK\n";
    }
    exit;
}
if( $cmd eq 'extract' ) {
    my $file = shift or die( "no file" );
    system( "rm $file; unzip $file.zip;" );
    system( "$0 storable <$file" );
    exit;
}
die( "Bad command $cmd\n" );
exit;

And here are the commands (Yes, it fails with newer versions of Perl, and yes in real life there's error checking):

# ./IUZ-Storable.pl write foo  # Write hash to file "foo" and zip
  adding: foo (stored 0%)
# ./IUZ-Storable.pl storable <foo  # Read with Storable and verify
OK
# ./IUZ-Storable.pl uncompress <foo # Read foo (transparent mode) via IUU fails
Magic number checking on storable string failed at /usr/lib/perl5/5.8.8/i386-linux-thread-multi/Storable.pm line 443, at ./IUZ-Storable.pl line 38.
# ./IUZ-Storable.pl uncompress <foo.zip # Read Zip archive via IUU fails
Magic number checking on storable string failed at /usr/lib/perl5/5.8.8/i386-linux-thread-multi/Storable.pm line 443, at ./IUZ-Storable.pl line 38.
# ./IUZ-Storable.pl extract foo   # Extract from zip file and read/verify with Storable
Archive:  foo.zip
 extracting: foo
OK
#

FWIW, strace doesn't show anything odd on the system side of the pipe.

strace -f ./IUZ-Storable.pl uncompress <foo
(...)
read(0, "pst0\4\t\0041234\4\4\4\10\3\1\0\0\0\n\5value\3\0\0\0k"..., 4096) = 34
write(2, "Magic number checking on storabl"..., 148Magic number checking on storable string failed at /usr/lib/perl5/5.8.8/i386-linu (...)
# And here's the entire Storable file (34 bytes);
## od -tao1 foo
0000000   p   s   t   0 eot  ht eot   1   2   3   4 eot eot eot  bs etx
        160 163 164 060 004 011 004 061 062 063 064 004 004 004 010 003
0000020 soh nul nul nul  nl enq   v   a   l   u   e etx nul nul nul   k
        001 000 000 000 012 005 166 141 154 165 145 003 000 000 000 153
0000040   e   y
        145 171
0000042

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions