Front page | perl.perl5.porters |
Postings from September 2013
Re: [perl #119555] require should not clobber $! and $^E on success
Thread Previous
From:
Christian Millour
Date:
September 4, 2013 18:07
Subject:
Re: [perl #119555] require should not clobber $! and $^E on success
Message ID:
522776C9.6010608@abtela.com
Fist a big thanks to whoever took the pain to properly resend this
ticket to p5p (it apparently got lost). For the sake of those following
this on rt.perl.org, hereafter is a copy of a clarification exchange I
had with Zefram.
Le 02/09/2013 12:55, Zefram a écrit :
> Christian Millour wrote:
>> In line with this effort, and considering the problem outlined above,
>> require should do the right thing and restore on success the values
>> of $! and $^E as they were on invocation.
>
> This argument can be used to justify saving and restoring $! and $^E
> around *any* operation. With Carp there was some historical
justification
> that it had attempted to preserve $!, and I was willing to make that
> work properly. require has never attempted to preserve $!, and in fact
> the clearing suggests that it's actively attempting to signal its own
> status through $!, which restoration would break.
>
> -zefram
>
Damn. I have spent ages trying to try and craft this ticket so to avoid
this misunderstanding and didn't succeed . Sorry if I was unclear. I am
not advocating saving and restoring $! and $^E blindly within require,
but only when require is *successful*.
If the pseudocode in the pod is to be trusted, require signals errors by
*dying*, and obviously in that case $! and $^E sould *not* be restored,
so that the calling code may access those and react accordingly (see
http://www.nntp.perl.org/group/perl.perl5.porters/2012/12/msg196988.html).
I am specifically *not* advocating using "local ($!, $^E);" at the start
of require, but rather the following pseudocode
sub require {
my ($filename) = @_;
my @saveerrs = ($!, $^E); # *added*
if (exists $INC{$filename}) {
return 1 if $INC{$filename};
die "Compilation failed in require";
}
my ($realfilename,$result);
ITER: {
foreach $prefix (@INC) {
$realfilename = "$prefix/$filename";
if (-f $realfilename) {
$INC{$filename} = $realfilename;
$result = do $realfilename;
last ITER;
}
}
die "Can't find $filename in \@INC";
}
if ($@) {
$INC{$filename} = undef;
die $@;
} elsif (!$result) {
delete $INC{$filename};
die "$filename did not return true value";
} else {
($!, $^E) = @saveerrs; # *added*
return $result;
}
}
which restores $! and $^E on success, and leaves them untouched for
inspection on failure.
Le 02/09/2013 13:40, Zefram a écrit :
> Christian Millour wrote:
>> I am not advocating saving and restoring $! and $^E blindly
>> within require, but only when require is *successful*.
>
> Thanks for the clarification. I did miss that detail of your original
> message (which on rereading I can now see there). But it's still an
> awfully broadly applicable argument. What else should work to preserve
> $! on success? Or rather, what should not?
>
> -zefram
>
for those on p5p who wonder what the hell we are talking about, and
awaiting sync between perlbug and p5p, the original report can be found at
https://rt.perl.org:443/rt3/Ticket/Display.html?id=119555
To answer your question, my main focus with #116118 has been on trying
to ensure that croak/confess, as an error reporting mechanism, indeed
report faithfully on the error rather than corrupting it (in the sense
that $! and $^E are still fully available, especially their numerical
values, when the error is caught).
What I am really after is the following strategy for programmatic error
handling (see #116118 for the whole story) :
eval { some_sub_that_might_die_or_croak; 1 } or do {
my ($evalerr, $e, $se) = ($@, $!, $^E);
if (ref $evalerr) {
... # deal with exception object
} elsif (I_can_make_sense_of_this_error_string($evalerr)) {
... # deal with error string
} else { # deal with numerical errors
if ($e == ENOENT) {
...
} elsif {$e == EACCES) {
...
etc.
}
};
[the underlying issue being that it is often impossible to make sense of
$evalerr above when you have to support different OS, versions of perl,
and locales, as the strings handed back by die/croak "oops: $!, $^E" are
then essentially unpredictable]
Your "local ($!, $^E);" patch on longmess/shortmess went a long way
towards that goal. #119555 is intended as a complement, to prevent the
lurking bug currently inherent with the 'lazy loading of Carp' idiom.
One remaining problem is as follows:
Le 31/12/2012 18:27, Jan Dubois a écrit :
> Even then you still have the problem that any DESTROY method run while
> unwinding the stack back to the eval() handler may modify $! and $^E
> again. So these values would also need to be handled similar to $@.
Once this is solved I believe my concerns with error reporting will have
been handled, so the argument might be less broadly applicable as you think.
As a general rule, I think ops and subs and constructs should not
clobber (or reset) $! and $^E when successfull. But I also understand
that such a requirement might be overkill and too costly to be applied
bluntly. Still, I hope to raise some awareness of the utility of not
corrupting gratuitously $! and $^E.
In the specific case of require, I believe that fixing it as suggested
is easier and on the long term better than hunting for all instances of
the 'lazy loading of Carp' idiom. YMMV.
Christian
Thread Previous