What things in CORE Perl set the ERRNO ($!) on success?

Viewed 176

According to PerlIO::scalar you can open a filehandle to a scalar,

open my $fh, ">",  \$scalar or die;

How come $! gets set when you use this though?

use strict;
use warnings;
use autodie;
use Test::More tests => 3;

is ( $!, '', '$! is not set' );

my $output;
open ( my $fh, '>', \$output );
print $fh "Hello, World!";

is ( $output, "Hello, World!", "Got the right output" );
is ( $!, '', '$! is not set' );

This is really weird: fork returns the pid so you determine failure by looking at $!. I thought $! only got set on failure though. The docs make it clear that this variable doesn't get cleared on success,

Many system or library calls set errno if they fail, to indicate the cause of failure. They usually do not set errno to zero if they succeed. This means errno, hence $!, is meaningful only immediately after a failure - perldoc perlvar

So generally you have to clear $! after a failure. But should we always clear it after a success too? What things set $! on success?

2 Answers

How come $! gets set when you use this though?

$! gets set by successful calls all the time. That's why $! is only meaningful when a function indicates $! is meaningful (by returning an error).

Original bug on Perl opened here

Not a bug in Perl. As per the documentation you quoted, $! is only meaningful after a failed call, so the fact that you assign meaning to its value after a successful call is a bug in your code.

So generally you have to clear $! after a failure.

You don't ever need to clear $!.

This is really weird: fork returns the pid so you determine failure by looking at $!.

No, fork returns undef on error. Only check $! if fork returns undef.

my $pid = fork();
defined($pid)
   or die($!);

if (!$pid) {
   my $rv;
   if (!eval { $rv = child(); 1 }) {
      # Let's be careful in case the stringification of $@ fails.
      my $e = $@;
      eval { warn($e); 1 }
         or warn("Unknown error");

      # Attempt to return something meaningful like Perl does.
      exit( $! || ($? >> 8) || 255 );
   }

   exit($rv);
}

waitpid($pid, 0);

Answer rewritten

In the question I said,

This is really weird: fork returns the pid so you determine failure by looking at $!.

This was not true: fork indicates failure by returning undef for the pid. From perldoc -f fork,

It returns the child pid to the parent process, 0 to the child process, or undef if the fork is unsuccessful.

From the bug report, you can see:

There are some cases where you have to clear it beforehand because no other mechanism is given to indicate an error - Grinnz

But, it appears fork is not one of those cases. So it seems like anything can put anything in $!. That is to say, even when an error has not occurred $! could be populated. But only when you rely on $! for the presence of an error should you clear it beforehand, and you should never rely on $! for error-status unless required.


Original bug on Perl opened here

Related