Why doesn't use warnings FATAL => 'all' seem to work? - perl

This script:
use warnings FATAL => 'all';
warn 'warning';
die 'death';
...results in 'warning' getting logged, but doesn't die at that point, instead dying with 'death'.
I have a mod_perl module that overrides $main::SIG{__DIE__} to basically spit out die() messages to the browser during development, but it does not touch SIG{__WARN__}, so what is happening here?
This is on perl 5.10.1 on Windows Server 2003, with "-w" in PerlSwitches.

It doesn't seem to work because your test isn't testing what you want to test. Try this:
use warnings FATAL => 'all';
print undef;
die 'death';
Just as a no warnings will not prevent warn from working, warnings FATAL will not make warn die.

You misunderstood the purpose of the warnings pragma. It is there to emit a warning message for completely legal, but possibly wrong operations. Example:
use warnings;
my ($x, $y) = ("hello", "world");
say "same" if $x == $y;
→ Argument "world" isn't numeric…. We can make certain categories produce fatal errors with use warnings FATAL => $CATEGORY with categories like numeric or uninitialized. The all category represents all categories.
It does not change the semantics of every warn to die. You can do this yourself, e.g. with overriding a local $SIG{__WARN__}, or creating a warn function that does croak #_. You can even override CORE::GLOBAL::warn to change all warns, even if they are in other modules.
The CGI::Carp module has a warningsToBrowser option; you may want to look at the source code to see how it's implemented.

Related

Wrapping Perl "die" and "warn" in a utility subroutine

I want to write a small subroutine that can decorate all error messages in a consistent way instead of having to copy it all around my program.
However I want the line numbers to be from where it was called, not from where the die/warn occurred.
In C I would just use a preprocessor macro, but Perl does not have those. What is the best way to implement this?
Use Carp for warnings/errors. You can use __WARN__ and __DIE__ hooks to affect what warn prints to the STDERR stream and how die is thrown. Note that they are quite different.
use warnings;
use strict;
use feature 'say';
use Carp;
$SIG{__WARN__} = \&wrap_warn;
sub wrap_warn {
print "WARNING: #_";
}
sub level_2 {
say "Print from level_2";
carp "carp from level_2(#_)";
}
sub level_1 {
level_2(#_);
}
level_1("from main");
prints to STDOUT
Print from level_2
WARNING: carp from level_2(from main) at wrap_warn.pl line 19.
main::level_2('from main') called at wrap_warn.pl line 15
main::level_1('from main') called at wrap_warn.pl line 22
If you want this to still go to STDERR then use print STDERR "WARNING: #_";
Make sure to carefully read about %SIG in perlvar and warn, at least.
While it seems that you want this to be global, I'd like to mention that one generally wants to local-ize changes like this one. There's an example in this post, and more out there.
Adding the following will add stack traces to exceptions and warnings:
use Carp::Always;
For the occasional use, use the following to avoid modifying your program:
perl -MCarp::Always script args
or
PERL5OPT=-MCarp::Always script args

Perl exit on warning

I'd like a perl script to exit with error code immediately on any kind of warning.
For example, on an "argument ... isn't numeric in addition" warning.
How can one do this?
Thank you in advance.
The warnings pragma has the FATAL option:
use warnings FATAL => 'all';
toolic's answer of use warnings FATAL => 'all'; is correct, but there are some caveats. There are some warnings emitted by internal perl functions that really don't expect to be dying. There's a list of those unsafe-to-fatalize warnings in perldoc strictures.
As of version 2.000003 of strictures, it enables warnings as follows:
use warnings FATAL => 'all';
use warnings NONFATAL => qw(
exec
recursion
internal
malloc
newline
experimental
deprecated
portable
);
no warnings 'once';
See https://metacpan.org/pod/strictures#CATEGORY-SELECTIONS for the full rationale.
Instead of copy/pasting the above lines into your code, you could of course just
use strictures 2;
which also enables strict for you.
(You might have to install strictures first, though.)
Not mentioned yet, but you can set a __WARN__ handler and do what you like there.
$SIG{__WARN__} = sub {
die "This program does not tolerate warnings like: #_";
};

How do I conditionally make warnings fatal?

I want to have fatal errors that can be demoted to warnings (or conversely, warnings that can be promoted to fatal errors) depending on the user's preference. At present, I'm using die and overriding it like this:
my $force;
BEGIN {
no warnings 'once';
Getopt::Long::Configure('pass_through');
GetOptions('force', \$force);
*CORE::GLOBAL::die = sub { warn #_ } if $force;
Getopt::Long::Configure('no_pass_through');
}
use My::Module;
...
die "maybe";
...
exit(1) if $force;
exit(0); # success!
I don't like this approach, mostly because there are a few places where I still want to die (e.g. missing command-line arguments). I'd rather change (most) instances of die to warn and do a conditional use warnings FATAL => 'all'1. The problem is that use warnings is lexically scoped, so this is ineffective:
if (!$force) {
use warnings FATAL => 'all';
}
Attempting to use a postfix conditional is a syntax error:
use warnings FATAL => 'all' unless $force;
and use can't be used in an expression:
$force or use warnings FATAL => 'all'; # syntax error
I can think of various distasteful work-arounds (Defining my own warn/die, duplicating my main script code in an if/else, etc.) but am seeking an elegant solution that conditionally applies use warnings in the current lexical scope. (Applying it in the parent scope would work as well but would likely require dark magic.)
1: Actually, I want to add use warnings::register to my modules and use warnings FATAL => 'My::Module' to my script, but the distinction is unimportant for the purposes of this question.
You could try:
use if !$force, warnings => qw( FATAL all );
Yes, there's a module called if that is distributed with Perl to make it really easy to do conditional imports.
Note that this is evaluated at compile time, so $force needs to be defined at compile time. (Probably within a BEGIN { ... } block.) Based on the code samples in your question, you seem to have figured that part out already though.
Alternatively, more manual:
BEGIN {
require warnings;
warnings->import(qw/ FATAL all /) unless $force;
}
A completely different approach would be to use a signal handler $SIG{__WARN__} or $SIG{__DIE__} to decide to die or not at run-time.

How can I suppress warnings from a Perl function?

In PHP you might use # in front of function call to suppress warnings returned.
Is there something similar in Perl?
This feature of PHP is crazy and should be avoided whenever possible.
Perl has two kinds of exceptions: Fatal errors and warnings. Warnings may either be emitted by Perl itself, or by user code.
Inside a certain static/lexical scope, Perl's builtin warnings can be switched off like:
use warnings;
foo();
sub foo {
no warnings 'uninitialized'; # recommended: only switch of specific categories
warn "hello\n";
1 + undef; # Otherwise: Use of uninitialized value in addition (+)
}
Output: hello on STDERR.
(A list of all warnings categories can be found here )
But this can't be used to remove warnings from code you are calling (dynamic scope). This also doesn't silence user-defined warnings.
In this case, you can write a handler for the __WARN__ pseudo-signal:
use warnings;
{
local $SIG{__WARN__} = sub { };
foo();
print "bye\n";
}
sub foo {
warn "hello\n";
1 + undef;
}
Output: bye on STDOUT.
We can abstract that into a function muffle:
sub muffle {
my $func = shift;
local $SIG{__WARN__} = sub { };
return $func->(#_);
}
muffle(\&foo, 1, 2, 3); # foo(1, 2, 3)
However, this is an incredibly dumb thing to do:
Warnings point to potential problems and bugs. Fix those instead of ignoring them.
Don't activate built-in warnings in the first place for categories you aren't interested in. E.g. many people are perfectly happy that an undef value stringifies to the empty string, and don't want any warning for that.
The strategies outlined here do not handle fatal exceptions, use Try::Tiny instead.
You could also just run perl -X and disable all warnings.
I think there are perfectly valid reasons for doing this FWIW.
Easier way is to use no warnings; See perldoc link for more information. Wrap the statement giving warning in curly braces to get rid of the warning message.
E.g.
{
no warnings;
<statement giving warning>
}

How can I use Test::NoWarnings to catch redefinition errors for EXPORT()ed subroutines when loading modules in sequence

I'm working with a Test::More-based unit test for part of our codebase that loads all of our in-house modules in sequence with use_ok(). I'd like to make warnings fatal to the unit test so that we can more easily catch regressions.
It was suggested here that I use Test::NoWarnings, and indeed that seems to be what I am looking for.
The script is here:
#!/usr/bin/perl -w
use File::Find;
use File::Spec;
use Test::More;
use Test::NoWarnings;
# Determine the filepaths of every .pm file in the lib directory
my #files;
File::Find::find(
sub
{
if (/\.pm$/)
{
push(#files, $File::Find::name);
}
},
"$ENV{'CODE_ROOT'}/lib"
);
done_testing(scalar(#files) + 1);
use lib "$ENV{'CODE_ROOT'}/lib";
foreach my $file (#files)
{
# <code removed for brevity: format file name into Module::Hierarchy::For::Use>
use_ok($includeString);
}
1;
I have come across a few cases in which subroutines EXPORT()ed by different modules raise redefinition warnings, but these warnings are not caught by the Test::NoWarnings module. In contrast, a warning due to a lower-case attribute declaration is caught correctly.
To be clear, I have read the caveats about use of EXPORT() vs EXPORT_OK(), and the sources of the warnings themselves are being dealt with. I am specifically wondering whether my assumptions about the behaviour of Test::NoWarnings are correct, and if so, how I can alter the unit tests so that such things are caught.
If you want to make warnings fatal, what about just turning that on?
use strict;
use warnings FATAL => 'all';
Yes, the POD for warningspragma does caution strongly against the use of this option:
FATAL warnings should be used with care, particularly FATAL => 'all'
and
use of FATAL => 'all' is discouraged
But I think use in a regression or unit test is a valid use case. I've been using this in all of my unit and regression tests for a long time now with no unintended consequences (yet). I think Test::Warn and Test::NoWarnings are best used for catching your modules' own warnings, both expected and unexpected.
use strict;
use warnings FATAL => 'all';
use Test::More;
use Test::Warn; # test for our own expected warnings
require Test::NoWarnings; # REQUIRE to suppress auto test at program exit
my $tCnt = 0;
ok(1, "first test"); $tCnt++;
warning_like { warn("my warn") } (qr/my warn/), "caught warning"; $tCnt++;
ok(1, "made it to the end"); $tCnt++;
Test::NoWarnings::had_no_warnings(); $tCnt++;
done_testing($tCnt);
If you throw in a statement like length("123"); (void context) the compile-time warning will boot you right out with the FATALS => 'all'in effect. Without it, the all the tests run and pass, with no inkling of a potential problem.