Subject: | Corner-case bug in Error.pm |
Date: | Mon, 16 Jan 2006 19:17:47 +0000 |
To: | bug-Error [...] rt.cpan.org |
From: | Paul LeoNerd Evans <leonerd [...] leonerd.org.uk> |
I have been fiddling with the Error.pm module for exception handling. I
have found a corner-case where the "finally" block does not get run.
Given as try / catch / finally blocks are anonymous subs, I find I have
to use something like the following workaround if I want to get the
containing function to return a value:
sub test
{
my $ret;
try {
some(); code(); here();
}
catch Some::Exception with {
$ret = ErrorCode;
goto ABORT:
};
return undef;
ABORT:
return $ret;
}
This works correctly. However, in the presence of a "finally" block, it
breaks. The non-local "goto ABORT" skips over the finally handler,
causing it not to be called. This has bad consequences if e.g. it
contains file unlocking code, for example.
I have found a solution to this, in other code I have which wraps
anonymous subrefs. This involves a special object class created just for
the purpose:
package Cleanup::Handler;
sub new
{
my $class = shift;
my ( $code ) = @_;
my $self = \$code;
return bless $self, $class;
}
sub DESTROY
{
my $self = shift;
my $code = $$self;
$code->();
}
1;
...
{
my $cleanup = new Cleanup::Handler( sub { unlock() } );
lock();
eval { $othercoderef->() };
}
Now, even if the $othercoderef uses a non-local goto, the $cleanup
variable codes out of scope, gets garbage collected, and the DESTROY
handler is called. The unlock() function still gets called.
Perhaps you would be able to work this sort of logic into the "try"
function in Error.pm? Or alternatively, I could take a look at the code
and provide a patch...
--
Paul "LeoNerd" Evans
leonerd@leonerd.org.uk
ICQ# 4135350 | Registered Linux# 179460
http://www.leonerd.org.uk/
Message body not shown because it is not plain text.