Front page | perl.perl5.porters |
Postings from July 2014
Re: [perl #119555] require should not clobber $! and $^E on success(impact on autouse and autodie)
Thread Previous
|
Thread Next
From:
Christian Millour
Date:
July 23, 2014 09:01
Subject:
Re: [perl #119555] require should not clobber $! and $^E on success(impact on autouse and autodie)
Message ID:
53CF79BE.9010906@abtela.com
Le 02/09/2013 11:28, Christian Millour (via RT) a écrit :
> -----------------------------------------------------------------
> [Please describe your issue here]
>
> On success, require resets $! and clobbers $^E (on platforms where $^E
> is distinct from $!, such as Windows). It would be better to restore the
> previous values of $! and $^E.
Let me restate this, and add some motivation. To recall, the problem
arises when you try to deal with the numerical values or $! and $^E for
programmatic error handling, rather than with their string counterpart.
Let us start with the baseline sample using die :
> [cm@COS63 ~/blead/perl-git]$ ./perl -E 'eval { $! = 21; die "fail:$!"; 1 } or do { say "must handle numerical error ", 0+$!}'
> must handle numerical error 21
So far so good.
We are taught about using Carp::croak instead of die when authoring
modules. Thanks to some foresight from authors of Carp, and later work
by its maintainer (thanks, Zefram :-) ), Carp::croak (and confess) do
attempt to preserve $!, so the error recovery strategy outlined above,
i.e. dealing with the numerical value of $!, can be used :
> [cm@COS63 ~/blead/perl-git]$ ./perl -E 'eval { use Carp; $! = 21; croak "fail:$!"; 1 } or do { say "must handle numerical error ", 0+$!}'
> must handle numerical error 21
what the croaking code cannot do however is 'autouse Carp', even though
this is the very example provided in the perldoc for autouse :
> [cm@COS63 ~/blead/perl-git]$ ./perl -E 'eval { use autouse Carp => qw(croak); $! = 21; croak "fail:$!"; 1 } or do { say "must handle numerical error ", 0+$!}'
> must handle numerical error 0
The problem arises through no fault of Carp or autouse, but because
require resets $! on success. This may be worked around by preloading Carp:
> [cm@COS63 ~/blead/perl-git]$ ./perl -MCarp -E 'eval { use autouse Carp => qw(croak); $! = 21; croak "fail:$!"; 1 } or do { say "must handle numerical error ", 0+$!}'
> must handle numerical error 21
but that pretty much defeats the purpose of autouse, and makes for a
nasty trap for the unwary. And any pre-autouse code that uses a similar
mechanism, as in
package Whatever;
sub croak {
require Carp;
goto &Carp::croak;
}
suffers from the same problem.
Possibly more serious, given e.g. how the latest edition of "Modern
Perl" by chromatic embraces autodie
(http://www.modernperlbooks.com/mt/2012/10/why-the-modern-perl-book-uses-autodie.html),
the croaking code cannot 'use autodie' either:
> [cm@COS63 ~/blead/perl-git]$ ./perl -MCarp -E 'eval { use autodie qw(open); open (A, ">", "."); 1 } or do { say "must handle numerical error ", 0+$!}'
> must handle numerical error 0
again through no fault of autodie, but for the same reason as before
(require resetting $! on success). This may currently be worked around
by preloading autodie::exception :
> [cm@COS63 ~/blead/perl-git]$ ./perl -Mautodie::exception -E 'eval { use autodie qw(open); open (A, ">", "."); 1 } or do { say "must handle numerical error ", 0+$!}'
> must handle numerical error 21
but is fragile and IMHO raises obscurity to a new level of darkness :-/
Actually, if the croaking code uses autodie, then the client code may
access the numerical value of $! from the autodie::exception instance :
> [cm@COS63 ~/blead/perl-git]$ ./perl -E 'eval {use autodie qw(open); open (A, ">", "."); 1 } or do { say "must handle numerical error ", 0+$@->errno}'
> must handle numerical error 21
unfortunately the doc for errno in autodie::exception states that 'This
method will leave the main autodie::exception class' so it cannot be
relied on. Furthermore, autodie makes currently no provision for $^E.
On some systems $^E may be more specific than $!, and deserves to be
preserved as well. The examples above concentrated on $! for concision
but could obviously have been written with $^E instead.
----------- SO ? --------------
I can't think of a compelling reason for require to reset $! (and
corrupt $^E) when successful, instead of restoring their values on
entry. And indeed it seems to me that dSAVE_ERRNO, SAVE_ERRNO and
RESTORE_ERRNO exist in perl.h to deal with exactly such situations (and
furthermore DTRT wrt. $^E). An analysis together with a tentative patch
have been proposed here :
https://rt.perl.org/Public/Bug/Display.html?id=116118#txn-1181050 , and
no objection were raised.
Could this tentative patch please be updated as needed and
applied/smoked ? I can formalize a patch if needed but would rather have
the original author (Craig) get the credit.
Thanks for your time and consideration.
Christian
Thread Previous
|
Thread Next