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 28, 2014 22:46
Subject:
Re: [perl #119555] require should not clobber $! and $^E on success(impact on autouse and autodie)
Message ID:
53D6D2B5.4040208@abtela.com
Le 28/07/2014 05:01, Craig A. Berry a écrit :
> The problem is my patch doesn't actually do what you want.  It does
> successfully restore any errno that is set in pp_require while rifling
> through @INC trying to find the file being required (assuming the file
> is eventually found and successfully opened).
>
> But after it's opened, the file is sent to S_doeval to be compiled,
> and somewhere in there errno gets cleared again.  I haven't figured
> out exactly how or where yet.  There is a call to CLEAR_ERRSV(), which
> has been there in some form since Perl 5.000.  That might be what's
> clearing errno, or not; I don't know.  It doesn't look like it would,
> but maybe there's magic on PL_errgv or something.
>
> On the surface, it sounds reasonable that a successful require should
> leave errno in the state it was in prior to the require.  But nothing
> resembling a complete or well-though-out implementation has been
> proposed, and any change in this area will involve touching sensitive
> bits of the core that have been as they are for twenty years.  A
> reformulated patch is attached, but at best it's a partial solution.

Thank you for your time and efforts on this.

pp_require is indeed quite involved and I fully understand anyone being 
wary of touching it.

Still, according to the documentation, require dies on error, and 
otherwise survives. So irrespective of the internal causes of changes to 
$! and $^E, it should be OK to restore their values on entry in those 
cases where require does not die. In Perl :

sub new_require {
   my ($e, $se) = ($!, $^E);
   old_require $_[0];       # dies on error...
   ($!, $^E) = ($e, $se);   # ... and otherwise restore $! and $^E
}

While not strictly equivalent, and as an experiment, I wrapped the 
existing pp_require, renamed pp_require1 but otherwise untouched, into a 
new pp_require tasked with saving/restoring $! and $^E :

PP(pp_require1)
{
... existing code
}
PP(pp_require)
{
     OP *op;
     dSAVE_ERRNO;
     op = Perl_pp_require1(
#ifndef PERL_IS_MINIPERL
                           my_perl
#endif
                           );
     if ((*_errno()) == 0)
         RESTORE_ERRNO;
     return op;
}

However crude and ill-mannered, this hack seemed to work. A variation on 
the above might be the best solution. A similar idea, implemented in the 
attached patch, is to dSAVE_ERRNO as you did, but to RESTORE_ERRNO 
before any return point that is not a DIE. I find four of those : two 
RETPUSHYES, one RETPUSHUNDEF, and the final return. I can't see how 
those RESTORE_ERRNOs could damage the working of pp_require, even with 
the recursive calls that seem to occur (via S_doeval). Note that the 
SETERRNO(0, SS_NORMAL) introduced in 
<http://perl5.git.perl.org/perl.git/commit/d8bfb8bddf933a815b590823bd52295534e6ded0?f=pp_ctl.c> 
has been removed because 1) it seems unrelated to the internal mechanism 
of pp_require, and 2) its effect would be nullified by the 
RESTORE_ERRNOs (at least on success).

This seems to work (one.pm is successfully required, without clobbering 
$! and $^E) :

blead(w32) $ echo 0 > zero.pm; echo 1 > one.pm
blead(w32) $ ../perl -IPerl -IRule -e 'for (@ARGV) { $! = $^E = 1; eval 
{require "$_"; 1} or print $@; print $_,q{ ==> $! = }, 0+$!, q{, $^E = 
}, 0+$^E, qq{ [$^E]\n}}' doesnotexist.pm zero.pm one.pm
Can't locate doesnotexist.pm in @INC (you may need to install the 
doesnotexist module) (@INC contains: Perl Rule 
D:/perls/blead/perl-git2/lib .) at -e line 1.
doesnotexist.pm ==> $! = 2, $^E = 2 [Le fichier sp cifi  est introuvable]
zero.pm did not return a true value at -e line 1.
zero.pm ==> $! = 1, $^E = 1 [Fonction incorrecte]
one.pm ==> $! = 1, $^E = 1 [Fonction incorrecte]
blead(w32) $

This is better than the stock perl (here strawberry perl portable 5.20)

Perl_5.20.0 $ echo 0 > zero.pm; echo 1 > one.pm
Perl_5.20.0 $ perl -IPerl -IRule -e 'for (@ARGV) { $! = $^E = 1; eval 
{require "$_"; 1} or print $@; print $_,q{ ==> $! = }, 0+$!, q{, $^E = 
}, 0+$^E, qq{ [$^E]\n}}' doesnotexist.pm zero.pm one.pm
Can't locate doesnotexist.pm in @INC (you may need to install the 
doesnotexist module) (@INC contains: Perl Rule 
C:/strawberry-perl-5.20.0.1-32bit-portable-PDL/perl/site/lib/MSWin32-x86-multi-thread-64int 
C:/strawberry-perl-5.20.0.1-32bit-portable-PDL/perl/site/lib 
C:/strawberry-perl-5.20.0.1-32bit-portable-PDL/perl/vendor/lib 
C:/strawberry-perl-5.20.0.1-32bit-portable-PDL/perl/lib .) at -e line 1.
doesnotexist.pm ==> $! = 2, $^E = 2 [Le fichier spécifié est introuvable]
zero.pm did not return a true value at -e line 1.
zero.pm ==> $! = 0, $^E = 6 [Descripteur non valide]
one.pm ==> $! = 0, $^E = 6 [Descripteur non valide]
Perl_5.20.0 $

In case of failure the values of $! and $^E do not seem much worse with 
the patch than without (given that for "did not return a true value" 
they are not set anyway, so may be a bit random...).

Comments/critics/smokes warmly welcome :-) Best regards,

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