Skip Menu |

This queue is for tickets about the Error CPAN distribution.

Report information
The Basics
Id: 17092
Status: resolved
Priority: 0/
Queue: Error

People
Owner: Nobody in particular
Requestors: leonerd [...] leonerd.org.uk
Cc:
AdminCc:

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



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/
Download signature.asc
application/pgp-signature 189b

Message body not shown because it is not plain text.

On Mon Jan 16 14:18:37 2006, leonerd@leonerd.org.uk wrote: Show quoted text
> I have been fiddling with the Error.pm module for exception
handling. I Show quoted text
> 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 Show quoted text
> 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; > } >
What I normally do instead is: (untested) sub test { my $ret = undef; try { some(); code(); here(); } catch Some::Exception with { $ret = ErrorCode; goto ABORT: }; return $ret; } And this will work with finally as well. So it might be an annoyance, but not one that is hard to overcome. At the moment, I've started maintaining my own branch of Error.pm with bug-fixes here: svn://svn.berlios.de/web-cpan/Error.pm/trunk/ If you're interested you can send me a patch that adds a test and fixes this issue. Note that at the moment, I'm leaning towards not "fixing" this, but a reasonable patch might convince me otherwise. And don't goto's out of functions generate warnings with "use warnings"? Regards, Shlomi Fish Show quoted text
> This works correctly. However, in the presence of a "finally" block,
it Show quoted text
> 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 Show quoted text
> 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 Show quoted text
> and provide a patch... >
Subject: Re: [rt.cpan.org #17092] Corner-case bug in Error.pm
Date: Fri, 31 Mar 2006 15:10:28 +0100
To: bug-Error [...] rt.cpan.org
From: Paul LeoNerd Evans <leonerd [...] leonerd.org.uk>
On Fri, 31 Mar 2006 04:30:45 -0500 (EST) " via RT" <bug-Error@rt.cpan.org> wrote: Show quoted text
> sub test > { > my $ret = undef; > > try { > some(); code(); here(); > } > catch Some::Exception with { > $ret = ErrorCode; > goto ABORT: > }; > > return $ret; > } > > And this will work with finally as well. So it might be an annoyance, > but not one that is hard to overcome.
Ah, but now consider the following: sub test { my $ret = undef; try { flock( $filehandle, LOCK_EX ); code(); } catch Some::Exception with { $ret = ErrorCode; goto ABORT; }, finally { flock( $filehandle, LOCK_UN ); }; return $ret; } This finally block will not get run if an exception is thrown, because the goto moves right over it. My cleanup-handler approach would solve this. Show quoted text
> At the moment, I've started maintaining my own branch of Error.pm with > bug-fixes here: > > svn://svn.berlios.de/web-cpan/Error.pm/trunk/ > > If you're interested you can send me a patch that adds a test and > fixes this issue. Note that at the moment, I'm leaning towards not > "fixing" this, but a reasonable patch might convince me otherwise. > > And don't goto's out of functions generate warnings with "use > warnings"?
No. This isn't a goto out of the function. It's within the same function. Well, it's from an inner closure, to its parent function. That is allowed. -- Paul "LeoNerd" Evans leonerd@leonerd.org.uk ICQ# 4135350 | Registered Linux# 179460 http://www.leonerd.org.uk/
On Fri Mar 31 09:10:58 2006, leonerd@leonerd.org.uk wrote: Show quoted text
> On Fri, 31 Mar 2006 04:30:45 -0500 (EST) > " via RT" <bug-Error@rt.cpan.org> wrote: >
> > sub test > > { > > my $ret = undef; > > > > try { > > some(); code(); here(); > > } > > catch Some::Exception with { > > $ret = ErrorCode; > > goto ABORT:
I'm sorry - the "goto ABORT" here was a typo. It should not be present. Show quoted text
> > }; > > > > return $ret; > > } > > > > And this will work with finally as well. So it might be an
annoyance, Show quoted text
> > but not one that is hard to overcome.
> > Ah, but now consider the following: > > sub test > { > my $ret = undef; > try { > flock( $filehandle, LOCK_EX ); > code(); > } > catch Some::Exception with { > $ret = ErrorCode; > goto ABORT; > }, > finally { > flock( $filehandle, LOCK_UN ); > }; > > return $ret; > } > > This finally block will not get run if an exception is thrown,
because Show quoted text
> the goto moves right over it. My cleanup-handler approach would
solve Show quoted text
> this. >
Yes, but why do you need the goto in the first place? Just assign the error code and then let the code drop to the finally. If you need a special case, just assign an error variable and then check for it after the finally. Show quoted text
> > At the moment, I've started maintaining my own branch of Error.pm
with Show quoted text
> > bug-fixes here: > > > > svn://svn.berlios.de/web-cpan/Error.pm/trunk/ > > > > If you're interested you can send me a patch that adds a test and > > fixes this issue. Note that at the moment, I'm leaning towards not > > "fixing" this, but a reasonable patch might convince me otherwise. > > > > And don't goto's out of functions generate warnings with "use > > warnings"?
> > No. This isn't a goto out of the function. It's within the same
function. Show quoted text
> Well, it's from an inner closure, to its parent function. That is > allowed. >
I see. OK. Regards, Shlomi Fish
Hi! I talked with LeoNerd about it on the IRC, and he said he now agrees that fixing this issue the way he proposed may break existing code, and so the behaviour of the code should not be modified. Like I said, I believe it's the expected behaviour. So I'm closing this bug and will soon release a new 0.XX version of Error.pm (identical to the current version) with no known bugs.