Skip Menu |

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

Report information
The Basics
Id: 93564
Status: new
Priority: 0/
Queue: IO-Compress

People
Owner: Nobody in particular
Requestors: SREZIC [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 2.064
Fixed in: (no value)



Subject: Protect against corruption when fork and write compressed files
The following perl script creates a gzipped file which causes the following error message when decompressed using zcat: gzip: /tmp/bla.gz: decompression OK, trailing garbage ignored The script: #!/usr/bin/perl use strict; use IO::Compress::Gzip; my $ofh = IO::Compress::Gzip->new("/tmp/bla.gz") or die; print $ofh "before fork\n"; if (fork == 0) { exit; } else { # sleep 1; print $ofh "in the parent\n"; } __END__ Dependending on timing (i.e. if the "sleep 1" in the above example is activated), the file contents could even be incomplete. This problem occurs in all perl classes which do some cleanup & flush stuff in their DESTROY methods. Traditionally people were told to use POSIX::_exit in the child, but this prevents running all DESTROY methods, not the "dangerous" ones. One could use Acme::Damn to "unbless" the problematic objects (this works here, too). Different modules have aditional approaches to protect from this problem. DBI for example has the InactiveDestroy and AutoInactiveDestroy attributes available, so a user can control which of the forked processes should "take over control", or automatically give control to the parent only. Perl/Tk remembers the $$ when creating the MainWindow, and does cleanup stuff only in the parent process (see "parent_pid" in Event/Event.xs in the Perl/Tk distribution). Something like the following would work for IO::Compress::Gzip: package MyGzip; use base 'IO::Compress::Gzip'; my %fh2pid; sub new { my($class, @args) = @_; my $self = $class->SUPER::new(@args); $fh2pid{$self} = $$; # $self is not hash-based, so store the pid elsewhere $self; } sub DESTROY { my $self = shift; my $fhpid = delete $fh2pid{$self}; if ($fhpid == $$) { $self->SUPER::DESTROY(@_); } else { warn "DESTROY not allowed in child process ($$ != $fhpid)"; # probably be silent here } } But it would be nice if something like this (maybe only activated with some options, e.g. the same ones like DBI uses) would be part of IO-Compress. Regards, Slaven