global level exception handling in perl - perl

I have written a perl program which internally calls three perl modules. My supervisor after reviewing the code asked me add global exception handling. I didn't understand what he meant by this. He also said use Eval to accomplish this.I am not sure how to use Eval so that it catches any exception in the enire perl module. Can anyone help me by providing links or by providing explanation?
Thanks in advance.

For each program he wants me to have an exception handling where in if something goes wrong it will be highlighted and it becomes easy for us to debug.
When an uncaught exception occurs, it is printed to STDERR. Your highlighting requirement is already being met.
Exceptions messages already include the line number at which they were thrown (unless specifically suppressed), so some information to help debug is already available.
$ perl -e'sub f { die "bar" } f("foo")'
bar at -e line 1.
Adding use Carp::Always; to your scripts will cause a stack backtrace to be provided as well, providing more information.
$ perl -e'use Carp::Always; sub f { die "bar" } f("foo")'
bar at -e line 1.
main::f("foo") called at -e line 1

The problem you are given seems imprecise. "Global" and eval are somewhat contradictory, as
Borodin explained in his comment. Another way to do things "global" is given in ikegami's answer. However, since mentioning eval is specific here is a rundown on a very basic use of that.
You use eval on a block of code (or an expression but that is not what you want here). If a die is thrown anywhere inside that block, the eval catches that in the sense that you get the control back, the program won't just die. The variable $# gets filled with the error message. Then you can interrogate what happened, print out diagnostics, and possibly recover from the error.
eval { run_some_code(#args) };
if ($#) {
carp "Error in `run_some_code()`: $# --";
# Do further investigation, print, recover ...
}
You can have any code in the eval block above, it needn't be a single function call. Note that eval itself returns values that convey what happened (aside from $# being set).
As for the "global" in your problem statement, one thing that comes to mind is that you use eval at the level of main:: -- wrap in it any subs that themselves invoke functions from the modules.
A crucial thing about exceptions is that they "bubble up". When a die (Perl's sole exception) is thrown in a sub and the caller doesn't eval it, it goes up the call chain ... eventually showing up in main::, and if it is not caught (eval-ed) there then the program dies. So you can eval the top-level call in main:: and get to know whether anything anywhere below went wrong.
eval { top_level_call(); };
if ($#) {
warn "Error from somewhere in `top_level_call(): $#";
}
# Functions
sub top_level_call {
# doing some work ...
another_sub();
# doing more ...
}
sub another_sub {
# do work, no eval checks
}
If an error triggering a die happens in another_sub() its processing stops immediately and the control is returned to the caller, the top_level_call(). Since that sub doesn't check (no eval there) its execution stops at that point as well, and the control returns to its caller (in this example the main:: itself). So it eventually hits main::, and eval-ing there lets you know about errors and your program won't just exit.
Perhaps that's what was meant by "global" exception handling using eval.
You can do far more along these lines, if this is what you need to be doing. See eval for starters.
Update your question with clarifications, so you get more discussion here.
In practical terms, I would say that you equip yourself with some understanding of eval use as well as some of "global" error reporting, and then ask your supervisor for clarification and/or examples, as suggested by Borodin.

Related

Why do I need to localize $# before using 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";
};
}

How can I prevent my perl script from terminating if an exception is thrown in a module it uses?

I have a perl script, using standard-as-dirt Net::HTTP code, and perl 5.8.8.
I have come across an error condition in which the server returns 0 bytes of data when I call:
$_http_connection->read_response_headers;
Unfortunately, my perl script dies, because the Net::HTTP::Methods module has a "die" on line 306:
Server closed connection without sending any data back at
/usr/lib/perl5/vendor_perl/5.8.8/Net/HTTP/Methods.pm line 306
And lines 305-307 are, of course:
unless (defined $status) {
die "Server closed connection without sending any data back";
}
How can I have my script "recover gracefully" from this situation, detecting the die and subsequently going into my own error-handling code, instead of dieing itself?
I'm sure this is a common case, and probably something simple, but I have not come across it before.
Using eval to catch exceptions can occasionally be problematic, especially pre 5.14. You can use Try::Tiny.
You can use eval { } to catch die() exceptions. Use $# to inspect the thrown value:
eval {
die "foo";
};
print "the block died with $#" if $#;
See http://perldoc.perl.org/functions/eval.html for details.
Customizing the die to mean something else is simple:
sub custom_exception_handler { ... } # Define custom logic
local $SIG{__DIE__} = \&custom_exception_handler; # Won't die now
# Calls custom_exception_handler instead
The big advantage of this approach over eval is that it doesn't require calling another perl interpreter to execute the problematic code.
Of course, the custom exception handler should be adequate for the task at hand.

Why doesn't Perl warn for the redeclaration of a my() variable in the same scope?

use strict;
my $world ="52";
my $in = "42" ;
my $world="42";
my $out = "good" ."good";
chop($out);
print $out;
Do not worry about the code.The question is that I used my $world in two different lines but compiler didn't give any error but if we consider C language's syntax then we will get the error because of the redeclaration of variable. Why don't perl gives any error for redeclaration. I have one more question: What is the size of a scalar variable ?
1/ Variable redeclaration is not an error. Had you included "use warnings" then you would get a warning.
2/ By "size of scalar variable" do you mean the amount of data that it can store? If that's the case, Perl imposes no arbitrary limits.
You seem to be posting a lot of rather simple questions very quickly. Have you considered reading "Learning Perl"?
The question is my $world i used it in two different lines but compiler said no error but to the c we get error as redclaration of variable but why not in perl.
Simply because Perl isn't C, and redefining a variable isn't an error condition.
It can be a cause of unexpected behaviour though and would be picked up if you had use warnings; (as has been suggested to you before).
What is the size of scalar variable ? is there any size?
Define 'size'. Bytes? Characters? Something else? You might be looking for length
Because Perl likes to be robust. If you had warnings turned on, you would have heard about it.
"my" variable $world masks earlier declaration in same scope at - line 7.
Although USUW (use strict; use warnings;) is a good development practice, so would be using autodie--if autodie worried about syntax warnings. But the following, concept is roughly the same, to make sure that you're not avoiding any warnings.
BEGIN { $SIG{__WARN__} = sub { die #_; }; }
The above code creates a signal handler for warnings that just dies instead. However, I think this is better for a beginner:
BEGIN {
$SIG{__WARN__}
= sub {
eval {
# take me out of the chain, to avoid recursion
delete $SIG{__WARN__};
# diag will install the warn handler we want to use.
eval 'use diagnostics;';
$SIG{__WARN__}->( #_ ); # invoke that handler
};
exit 1; # exit regardless of errors that might have cropped up.
};
}
Anywhere you want, you can tell perl that you are not interested in changing your code to issue a particular category of warnings (and diagnostics will tell you the category!) and if you explicitly tell perl no warnings 'misc', not only will it not warn you, but it will also not fire off the warning handler, which kills the program.
This will give you a more c-like feel--except that c has warnings too (so you could implement a lexical counter as well...oh well.)

What are the best practices for error handling in Perl?

I'm learning Perl, and in a lot of the examples I see errors are handled like this
open FILE, "file.txt" or die $!;
Is die in the middle of a script really the best way to deal with an error?
Whether die is appropriate in the middle of the script really depends on what you're doing. If it's only tens of lines, then it's fine. A small tool with a couple hundred lines, then consider confess (see below). If it's a large object-oriented system with lots of classes and interconnected code, then maybe an exception object would be better.
confess in the Carp package:
Often the bug that led to the die isn't on the line that die reports.
Replacing die with confess (see Carp package) will give the stack trace (how we got to this line) which greatly aids in debugging.
For handling exceptions from Perl builtins, I like to use autodie. It catches failures from open and other system calls and will throw exceptions for you, without having to do the or die bit. These exceptions can be caught with a eval { }, or better yet, by using Try::Tiny.
Since I use Log::Log4perl almost everywhere, I use $logger->logdie instead of die. And if you want to have more control over your exceptions, consider Exception::Class.
It is better to catch your exceptions with Try::Tiny (see its documentation why).
Unless you've got a more specific idea, then yes you want to die when unexpected things happen.
Dying at the failure to open a file and giving the file name is better than the system telling you it can't read from or write to an anonymous undefined.
If you're talking about a "script", in general you're talking about a pretty simple piece of code. Not layers that need coordination (not usually). In a Perl Module, there is an attendant idea is that you don't own the execution environment, so either the main software cares and it catches things in an eval, OR it doesn't really care and dying would be fine. However, one you should try at a little more robustness as a module and just pass back undefs or something.
You can catch whatever dies (or croaks) in an eval block. And you can do your more specific handling there.
But if you want to inspect $! then write that code, and you'll have a more specific resolution.
Take a look at the near-universal standard of using strict. That's code that dies on questionable syntax, rather than letting you continue along.
So I think the general idea is: yes, DIE unless you have a better idea of how things should be handled. If you put enough foresight into it, you can be forgiven for the one or two times you don't die, because you know you don't need to.
The more modern approach is to use the Carp standard library.
use Carp;
my $fh;
open $fh, '<', "file.txt" or confess($!);
The main advantage is it gives a stack trace on death.
I use die but I wrap it in eval blocks for control over the error handling:
my $status = eval
{
# Some code...
};
If the 'eval' fails:
$status will be undefined.
$# will be set to whatever error message was produced (or the contents of
a die)
If the 'eval' succeeds:
$status will be the last returned value of the block.
$# will be set to ''.
As #friedo wrote, if this is a standalone script of a few lines, die is fine, but in my opinion using die in modules or require'd piece of code is not a good idea because it interrupts the flow of the program. I think the control of the flow should be a prerogative of the main part of the program.
Thus, I think, in module it is better to return undef such as return which would return undef in scalar context and an empty list in list context and set an Exception object to be retrieved for more details. This concept is implemented in the module Module::Generic like this:
# in some module
sub myfunc
{
my $self = shift( #_ );
# some code...
do{ # something } or return( $self->error( "Oops, something went wrong." ) );
}
Then, in the caller, you would write:
$obj->myfunc || die( "An error occurred at line ", $obj->error->line, " with stack trace: ", $obj->error->trace );
Here error will set an exception object and return undef.
However, because many module die or croak, you also need to catch those interruption using eval or try-catch blocks such as with Nice::Try
Full disclosure: I am the developer of both Module::Generic and Nice::Try.

Why does this Perl BEGIN block act differently in the debugger?

I have some Perl code that runs fine outside the debugger:
% perl somefile.pl
but when I run it inside the debugger:
% perl -d somefile.pl
it behaves differently.
The files in question (there are several) are part of the test suite for a large Perl module (~20K lines of code). The tests do a lot of setup work at compile time and use BEGIN blocks. Here's some minimal reproduction code:
BEGIN
{
package MyEx;
sub new { bless {}, shift }
package main;
eval { die MyEx->new };
if($#)
{
die "Really die" unless($#->isa('MyEx'));
}
}
print "OK\n";
If you put that in somefile.pl and run it, it prints "OK" as expected. If you run it in the debugger with perl -d somefile.pl, it dies with this error:
Can't call method "isa" without a package or object reference ...
The upshot is that $# is not an object when the code runs under the debugger. Instead, it's an unblessed scalar containing this string:
" at somefile.pl line 9
eval {...} called at somefile.pl line 9
main::BEGIN() called at somefile.pl line 16
eval {...} called at somefile.pl line 16
"
(Internal newlines and spacing preserved. That's the literal text, even the "..."s.)
I need code like this to run in the debugger. Using the debugger in the test suite is an important part of my workflow. The module uses exception objects and does a lot of stuff at compile time and expects an object thrown to be an object when caught.
My question (finally) is this: How can I get this to work? Is there a workaround? Is this a bug in the perl debugger module? What's the best way to go about getting this resolved? (I know that's several questions, but they're all related.)
I'm using perl 5.10.0 on Mac OS X 10.5.5.
The dieLevel thing suggested by Adam Bellaire looked promising, and indeed something (can't find out what) is setting it to 1 for me. But I set it to 0 using a ~/.perldb file and the problem persists. In fact, I set all three of the related settings to 0. My ~/.perldb file:
parse_options('dieLevel=0 warnLevel=0 signalLevel=0');
I confirmed that the settings are in effect by running the o command in the debugger. I see them all set to 0 when I run perl -de 0 and also when running the actual somefile.pl file.
Thanks, brian. I used perlbug to file a bug (RT 60890) and I've begun to sprinkle local $SIG{'__DIE__'} in all the appropriate places in my code. (I also noted in the bug that perldoc perldebug still seems to imply that the default dieLevel is 0.)
This is a problem with perl5db.pl creating __DIE__ handlers. If I localize $SIG{__DIE__} in your eval, things work as you expect.
eval {
local $SIG{__DIE__};
die MyEx->new
};
If you don't do that, you're getting the handler from DB::dbdie, which uses Carp::longmess. That shouldn't happen if dieLevel is 0, but by default it is 1, and it gets set to 1 if it is not defined. This was a patch to perl5db.pl back in 2001, and previously the default had been 0.
You're supposed to turn this off with:
PERLDB_OPT="dieLevel=0" perl5.10.0 -d program
But there is still a code reference in $SIG{__DIE__} after that, and it's a reference to dbdie. I think this is a bug in handling the global variable $prevdie in perl5db.pl's dieLevel. At the end of that subroutine, there is:
# perl5db.pl dieLevel, around line 7777
elsif ($prevdie) {
$SIG{__DIE__} = $prevdie;
print $OUT "Default die handler restored.\n";
}
But notice that after restoring $SIG{__DIE__}, it keeps the previous value in $prevdie, meaning whatever is in there leaks to another call. When I run that command line, there are two calls to dieLevel before it handles PERLDB_OPT, so $prevdie is probably dirty.
So, that's as far as I got before I didn't want to think about perl5db.pl anymore.
I consider it a bug any time code behaves differently in the debugger.
Your problem might be related to this: Debugger corrupts symbol table munging. Essentially, the debugger appears to play some tricks with local -- presumably as part of sandboxing things to provide interactivity. Obviously, messing with the symbol table can have unexpected side-effects. I'd guess that the debugger is localizing $# and thus obscuring your object. I can't think of a work-around.
Is it possible you have an RC file or environment variable (PERLDB_OPTS) that is modifying the dieLevel option of the debugger? I personally haven't used dieLevel but apparently when it's set to a value greater than zero it can force stack unwinding and "tends to hopelessly destroy any program that takes its exception handling seriously." (Quote from here).