Search code examples
perlfileerror-handlingstat

Custom error handling is catching errors that normally are not displayed


I am having a problem I can't seem to figure out and I hope you guys can help me.
The problem occurs when :

  • I use custom errorhandling
  • I use File::Stat in a seperate module

Example:

Main file

use strict;
use warnings;

# signal handling
$SIG{__DIE__} = sub {
    my $error = @_;
    chomp $error;
    print "die: $error\n";
};

require mod; 

mod->get_stat();

Module

package mod;

use strict;
use warnings;
use File::stat;

sub get_stat {
    my $file_path = "test.txt";
    my $file_size = stat($file_path)->size;
    print $file_size;
}

1;

This will cause the following output:

die: 1
die: 1
die: 1
die: 1
die: 1
4

Now, if I remove my custom error handling OR if I use mod instead of require the die's will not be displayed.

Interesting to see is that it does actually produce a result (test.txt is 4 bytes), meaning stat is working as it should.

So, why am I getting this error ? Is this really an error ? Does the default perl error handling ignore errors that are "1"?

EDIT
As Linus Kleen remarked, the reason I get "1" is because I am displaying the amount of elements in the array.

If I print out the content of the error instead, I get the following error:

die: Your vendor has not defined Fcntl macro S_ISVTX, used at c:/Perl64/lib/File/stat.pm line 37.

die: Your vendor has not defined Fcntl macro S_IFSOCK, used at c:/Perl64/lib/File/stat.pm line 41.

die: Your vendor has not defined Fcntl macro S_IFBLK, used at c:/Perl64/lib/File/stat.pm line 41.

die: S_IFFIFO is not a valid Fcntl macro at c:/Perl64/lib/File/stat.pm line 41.

die: Your vendor has not defined Fcntl macro S_IFLNK, used at c:/Perl64/lib/File/stat.pm line 41.

4

But still, I am getting an error that, without custom error handling, I do not get.


Solution

  • As explained in perlvar, due to an implementation glitch $SIG{__DIE__} hooks get called even when code dies inside an eval. When File::stat is loaded, it checks to see what constants Fcntl supports on your platform. It catches the errors caused by unsupported constants, but not before your hook sees them.

    You can tell if you're in an eval by checking the value of $^S. If it's not 0, then you're in an eval.

    $SIG{__DIE__} = sub {
        return unless defined $^S and $^S == 0; # Ignore errors in eval
        my ($error) = @_;
        chomp $error;
        print "die: $error\n";
    };
    

    You don't see the errors when you use instead of require because use is a compile-time operation and require is a run-time operation (as is setting %SIG). When you use mod and it uses File::stat, that all happens before you set up your hook. When you require mod, that doesn't happen until after you've installed your hook.