http://www.perlmonks.org?node_id=674657

jneil has asked for the wisdom of the Perl Monks concerning the following question:

Anybody know why the print statement is executed in this snippet? Somehow the 'die "ERROR:' statement doesn't actually die:

> perl -e 'use warnings FATAL => qw(all); eval { open(CMD, "_bad_exe_ a b c|") or die "open failed: $!\n" }; if($@){ die "ERROR: $@" }; print "HOW DID I GET HERE?\n"; while(<CMD>){}'
ERROR: Can't exec "_bad_exe_": No such file or directory at -e line 1.
HOW DID I GET HERE?


The snippet works as expected if you remove 'use warnings FATAL => qw(all)' or say 'no warnings qw(exec)' inside the eval block. This happens with Perl 5.8.8 and Perl 5.10.0.

Replies are listed 'Best First'.
Re: Weird use warnings FATAL behavior
by apl (Monsignor) on Mar 17, 2008 at 22:37 UTC
    The error you supply doesn't agree with the code you provided. (In addition, as per the FAQ, you should bracket your code with <code> and </code>).

    You dont't need the eval. Instead, use: open(CMD, "_bad_exe_") or die "open failed: $!\n" };

      The error supplied doesn't agree with the code provided, but I get it too. I'm using an older version of Perl, though. I don't have a newer version for that system, so it could have been fixed since.

      $ perl -e 'use warnings FATAL => qw(all); eval { open(CMD, "_bad_exe_ +a b c|") or die "open failed: $!\n" }; if($@){ die "$$: ERROR: $@" } +print "$$: HOW DID I GET HERE?\n"; while(<CMD>){}' 11089: ERROR: Can't exec "_bad_exe_": No such file or directory at -e +line 1. 11089: HOW DID I GET HERE? $ perl -v This is perl, v5.8.4 built for i386-linux-thread-multi ...

      Update: I added the PID to the error messages in case something went bad with the forking code.

      Update: Interestingly, open dies instead of returning an error. Notice how "open failed" is not part of the output. Are there two bugs here?

      Odd. Here's what happens with Ubuntu and 5.8.7:
      ww@GIG:~$ perl -v This is perl, v5.8.7 built for i486-linux-gnu-thread-multi (with 1 registered patch, see perl -V for more detail)

      OP's cut'n'pasted oneliner:

      ww@GIG:~$ perl -e 'use warnings FATAL => qw(all); eval { open(CMD, "_b +ad_e xe_ a b c|") or die "open failed: $!\n" }; if($@){ die "ERROR: $ +@" }; print "HOW DID I GET HERE?\n"; while(<CMD>){}' ERROR: Can't exec "_bad_exe_": No such file or directory at -e line 1. HOW DID I GET HERE? ww@GIG:~$
Re: Weird use warnings FATAL behavior
by kyle (Abbot) on Mar 18, 2008 at 03:44 UTC

    Hmmm, look at this...

    use warnings FATAL => qw(all); eval { open(CMD, "_bad_exe_ a b c|") or die "does not happen" }; die "die \$\@ ERROR: $@\n"; while(<CMD>){} __END__ die $@ ERROR: Can't exec "_bad_exe_": No such file or directory at ... + line x. die $@ ERROR:

    How did that happen?

    This is perl, v5.8.8 built for x86_64-linux-gnu-thread-multi

      It looks like the child process tries to warn which gets turned into a die which gets caught by the eval and thus causes the child to continue on to the line after the eval instead of doing what it was planning to do after it warned.

      Not really that much of a surprise, IMHO, since you told it to do all of those things.

      Then the parent doesn't get tricky notice of the child being unable to exec (since you forced the child to get side-tracked) so open succeeds and the parent continues on from there.

      One bug is that $$ doesn't get updated since the forked code isn't expected to survive long enough to be able to run any Perl code that uses $$, so trying to report $$ just confuses things.

      - tye        

        One bug is that $$ doesn't get updated since the forked code isn't expected to survive long enough to be able to run any Perl code that uses $$

        aha! The last bit of the puzzle. I assumed reading $$ translated into a system call to fetch the PID. It never occured to me it might not be accurate.

Re: Weird use warnings FATAL behavior
by naikonta (Curate) on Mar 18, 2008 at 09:19 UTC
    OK, here is the expanded version of the original OP's oneliner, following tye's explanation:
    cat fatals.pl #!/usr/bin/perl use strict; use warnings FATAL => 'all'; my $cmd = shift || '_bad_exe_ a b c'; print "I'm parent with id $$\n"; eval { my $pid = open CMD, "-|"; if ($pid) { print "I'm forking a child with id $pid\n"; print while <CMD>; } else { #no warnings; # get rid of warnings on "Can't exec:..." print "[$$] I'm child, about to exec [$cmd]\n"; exec $cmd; } }; die "[$$] ERROR: $@" if $@; print "[$$]HOW DID I GET HERE?\n";
    Run with correct command (just as comparisson):
    $ perl fatals.pl ls I'm parent with id 6238 I'm forking a child with id 6239 [6239] I'm child, about to exec [ls] 642663.pl 642676.pl 642682.pl 644761.pl
    No problem there. Now, run with no args (default command):
    $ perl fatals.pl I'm parent with id 6240 [6241] ERROR: Can't exec "_bad_exe_": No such file or directory at fat +als.pl line 18. I'm forking a child with id 6241 [6241] I'm child, about to exec [_bad_exe_ a b c] [6240]HOW DID I GET HERE?
    So I guess, it's the child that triggers the "Can't exec ..." warning that gets "upgraded" into fatal error (due to FATAL), trapped in $@, and dies. The child dies, the parent doesn't, that's HOW DID I GET HERE, I suppose. OTOH, if the no warnings; is uncommented, then well, no "Can't exec..." warning, no $@ trapping, and the child lives pretending nothing happens, yet covering up by asking HOW DID I GET HERE.

    Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

      Ok, so the version with explicit forking shows what is happenng better. This was my example (jneil just posted it for me). So there is no perl bug?