I'm working on the "Error Handling and Reporting" chapter of Mastering Perl. In perlvar's entry for $#, it says:
The Perl syntax error message from the last eval() operator. If $# is the null string, the last eval() parsed and executed correctly (although the operations you invoked may have failed in the normal fashion).
Now I'm wondering when an eval might not execute correctly, leaving $# with an undefined value. Are there any such cases?
Here's one way to do it (but sit down before you read it. ;))
$# = 123;
eval q{
$# = 456;
print ">>>$#<<<\n";
goto SKIP;
};
SKIP:
print ">>>$#<<<\n";
The BACKGROUND section of the Try::Tiny docs contain some info on how $# can be clobbered and why Try::Tiny takes special care to avoid clobberage, and always tests the return value of eval rather than testing $# for truth. All of them are in there because someone ran into them at some point, but I think that the eval-in-DESTROY scenario is the one most likely to trip someone up. Basically, if die causes some object to go out of scope, and that object has a DESTROY that calls eval, then the value that you died with to begin with is irretrievably lost. Assuming the eval in the DESTROY doesn't throw an error, $# will be "" following the outer eval.
Who said anything about setting $# to undef?
"The last eval() parsed and executed correctly" doesn't make any sense: eval isn't parsed at runtime. Surely, it means "the last eval() whose expression was parsed and executed correctly". In other words, "the last eval() whose expression compiled and didn't throw any exceptions when executed".
>perl -MData::Dumper -e"$#=123; eval ''; print(Dumper($#));"
$VAR1 = '';
>perl -MData::Dumper -e"$#=123; eval '~~~'; print(Dumper($#));"
$VAR1 = 'syntax error at (eval 1) line 2, at EOF
';
>perl -MData::Dumper -e"$#=123; eval 'die q{x}'; print(Dumper($#));"
$VAR1 = 'x at (eval 1) line 1.
';
Related
I noticed in my program that an exception raised from IO::Pipe was behaving oddly, and I cannot figure out what it's doing (let alone how it's doing it). I've boiled it down to a simple example program:
use strict;
use warnings;
use Carp;
use IO::Pipe;
my($path) = shift;
my($bad) = shift || "";
eval {
if ($path =~ m{pipe}i) {
my($bin) = ($bad ? "/bin/lsddd" : "/bin/ls");
my($pipe) = IO::Pipe->new();
$pipe->reader("$bin -l .");
print "$_" while <$pipe>;
$pipe->close;
}
elsif ($path =~ m{croak}i) {
croak "CROAKED" if $bad;
}
else {
die "DIED" if $bad;
}
};
if ($#) {
my($msg) = $#;
die "Caught Exception: $msg\n";
}
die "Uh-oh\n" if $bad;
print "Made it!\n";
The example program takes two arguments, one to indicate which code path to go down inside the eval block, and the second to indicate whether or not to generate an error (anything that evaluates to false will not generate an error). All three paths behave as expected when no error is requested; they all print Made it! with no error messages.
When asking for an error and running through the croak or die paths, it also behaves as I expect: the exception is caught, reported, and the program terminates.
$ perl example.pl die foo
Caught Exception: DIED at example.pl line 23.
and
$ perl example.pl croak foo
Caught Exception: CROAKED at example.pl line 11.
eval {...} called at example.pl line 10
When I send an error down the IO::Pipe path, though, it reports an error, but the program execution continues until the outer die is reached:
$ perl example.pl pipe foo
Caught Exception: IO::Pipe: Cannot exec: No such file or directory at example.pl line 15.
Uh-oh
The first question is why -- why does the program report the "Caught Exception" message but not terminate? The second question is how do I prevent this from happening? I want the program to stop executing if the program can't be run.
There are two processes running after the eval in the case of interest. You can see this by adding a print statement before if ($#). One drops through eval and thus gets to the last die.
The reader forks when used with an argument, to open a process. That process is exec-ed in the child while the parent returns, with its pid. The code for this is in _doit internal subroutine
When this fails the child croaks with the message you get. But the parent returns regardless as it has no IPC with the child, which is expected to just disappear via exec. So the parent escapes and makes its way down the eval. That process has no $# and bypasses if ($#).
It appears that this is a hole in error handling, in the case when reader is used to open a process.
There are ways to tackle this. The $pipe is an IO::Handle and we can check it and exit that extra process if it's bad (but simple $pipe->error turns out to be the same in both cases). Or, since close is involved, we can go to $? which is indeed non-zero when error happens
# ...
$pipe->close;
exit if $? != 0;
(or rather first examine it). This is still a "fix," which may not always work. Other ways to probe the $pipe, or to find PID of the escapee, are a bit obscure (or worse, digging into class internals).
On the other hand, a simple way to collect the output and exit code from a program is to use a module for that. A nice pick is Capture::Tiny. There are others, like IPC::Run and IPC::Run3, or core but rather low-level IPC::Open3.
Given the clarifications, the normal open should also be adequate.
Adding use strict to a perl program disables an important warning message. Is this a bug in perl?
This little program has a problem
#!/usr/bin/perl -w
my $rule;
sub applyRule() {
eval $rule;
}
my $foo_bar;
$foo_bar = "mega-foo-bar-ness";
$rule = 's/#FOO_BAR/$foo_bar/g';
$_ = "Please replace #FOO_BAR with something.";
applyRule();
print STDERR "OUTPUT: $_\n";
and we get a helpful warning message when running that program:
$ ./test1.pl
Use of uninitialized value $foo_bar in substitution (s///) at (eval 1) line 1.
OUTPUT: Please replace with something.
Now add use strict;
#!/usr/bin/perl -w
use strict;
my $rule;
sub applyRule() {
eval $rule;
}
my $foo_bar;
$foo_bar = "mega-foo-bar-ness";
$rule = 's/#FOO_BAR/$foo_bar/g';
$_ = "Please replace #FOO_BAR with something.";
applyRule();
print STDERR "OUTPUT: $_\n";
The substitution just silently fails.
$ ./test1.pl
OUTPUT: Please replace #FOO_BAR with something.
When I have mysterious errors in perl should I always try removing use strict to see if I get some helpful warnings?
edit 1 stackoverflow is asking me to describe why this is not a duplicate of Why use strict and warnings?. This is a case where adding use strict results in fewer warnings, which makes debugging harder -- the opposite of what I expect use strict would do; the opposite of what is suggested in the answers to that question:
The pragmas catch many errors sooner than they would be caught otherwise, which makes it easier to find the root causes of the errors.
edit 2: For anyone else seeing this: another way is:
defined (eval $rule) or warn "eval error: $#\n";
because eval returns undefined if there is an error. The Programming Perl book states in the section about eval
If there is a syntax error or run-time error, eval returns the undefined value and puts the error message in $#. If there is no error, $# is guaranteed to be set to the null string, so you can test it reliably afterward for errors.
Note however that with versions prior to Perl 5.14 there can be problems relying on '$#`.
Instead of a warning, it throws an exception. And you aren't testing to see if eval gave an exception.
Try:
eval "$rule; 1" or warn "exception thrown: $#\n";
I have a Perl script which I cannot understand.
for $i(#myarr)
{
#some stuff
eval {
#some stuff
};
if($#)
{
print "*** $# ****";
}
}
What does that eval do? Is it a standard Perl command or just some sub?
What is the variable $#? It is currently printing a string but I don know where that string is coming from.
$# The Perl syntax error or routine error message from the last eval, do-FILE, or require command. If set, either the compilation failed, or the die function was executed within the code of the eval. please read this doc http://perldoc.perl.org/perlvar.html
To add to Suic’s answer, see the English module that lets you use more descriptive $EVAL_ERROR instead of $# and the Try::Tiny or TryCatch modules that avoid common traps associated with using eval for exception handling. Also, the next time you wonder about a Perl function, perldoc -f is your friend (like perldoc -f eval).
I'm aware of the fact that $# is a global variable, still I can't figure out why I need to localize it before using eval:
For instance:
eval { SOME_FUNC_THAT_MAY_DIE(); };
if ($#) {
print "An error occured!\n";
}
The only possible thing I can think of is, if some signal handler will call die at the same time I try to read $#, what am I missing here?
The reason to say local $# before calling eval is to avoid stepping on your caller's $#. It's rude for a subroutine to alter any global variables (unless that's one of the stated purposes of the subroutine). This isn't really an issue with top-level code (not inside any subroutine).
Also, on older Perl's, any eval called during object destruction would clobber the global $# (if the object was being destroyed because an exception was being thrown from an eval block) unless $# was localized first. This was fixed in 5.14.0, but many people are still running older Perls.
The Try::Tiny module documentation gives the rationale (as well as providing an alternative):
When you run an eval block and it succeeds, $# will be cleared, potentially clobbering an error that is currently being caught.
This causes action at a distance, clearing previous errors your caller may have not yet handled.
$# must be properly localized before invoking eval in order to avoid this issue.
More specifically, $# is clobbered at the beginning of the eval, which also makes it impossible to capture the previous error before you die (for instance when making exception objects with error stacks).
You don't need to, but if you wrote code like this, localizing $# would keep the first error as it was. and if you didn't write code like this, the local $# would have no effect. better would be to handle errors before running any extra code.
eval {
die "error 1\n";
};
foo();
print "processing $#\n";
sub foo {
#local $#;
eval {
die "error 2\n";
};
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I check if I have a Perl module before using it?
I'd like to eval a use statement similar to this: eval {use $foo;} but am having trouble with the correct syntax. I've tried various combinations of string interpolation, but the eval always succeeds even for a module that does not exist. Can someone give me hand with this one?
The idiom you are looking for is:
eval "use $module; 1" or ... ;
eval "use $module; 1" or warn "$module is not available: $#";
eval "use $module; 1" or die "This script requires $module";
eval "use $module; 1" or $module_available = 0;
eval "always succeeds" in the sense that program execution will continue no matter what code is evaluated -- that's really the whole point of an eval statement. If the evaluated string contained errors -- run time or compile time -- the return value of the eval call is undef and the special variable $# will be set with an appropriate error message.
The use statement, even when successful, does not return a value. That's why this idiom includes the "; 1" at the end.
use is a keyword that is processed during compilation, as is mentioned in the comments, it does require you to use bareword arguments. That is, no variables.
Now, I can't get an eval { use $foo } to even compile, because it causes a syntax error, so the script is never run. I'm not sure what you mean exactly by "always succeeds", unless you mean the opposite: "always fails".