develooper 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


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About