I've recently been working on some code to catch errors throughout our code base (I.E. do a try/catch at the very top level of our Perl code). To my distress, I find that Perl stack traces omit stack frames! Gaaa! I'm looking for insight into why these stack frames are gone. The documentation for caller() says stack frames can be 'optimized away'. But really, it's so annoying to have them gone. Is there a way to coax Perl into including them? Is there a performance penalty for doing so? Below is a trivial example. As you will see, neither bar() nor bletch() are included in the stack trace. A sad omission that causes me to have to trace the code by hand.
Any insights received with gratitude.
Leonard
Here is foo.pl
use strict;
use warnings;
use Devel::StackTrace;
use Try::Tiny;
foo();
sub foo {
print "In foo\n";
try {
bar();
}
catch {
my $trace = Devel::StackTrace->new();
print $trace->as_string;
};
}
sub bar {
print "In bar\n";
bletch();
my $more_stuff = 123;
return $more_stuff;
}
sub bletch {
print "In bletch\n";
my $not_so_defined;
$not_so_defined->barf();
print "Unlikely to be printed\n";
}
And here is what gets printed when foo.pl is run:
In foo
In bar
In bletch
Trace begun at foo.pl line 17
main::__ANON__('Can\'t call method "barf" on an undefined value at ./foo.pl line 32.^J') called at /vcm/home/apps/perl-5.12.1/lib/site_perl/5.12.1/Try/Tiny.pm line 100
Try::Tiny::try('CODE(0xf503a0)', 'Try::Tiny::Catch=REF(0x1035ca0)') called at foo.pl line 19
main::foo at foo.pl line 9
To me, it looks like there's not. At least, not short of creating the stack frame deeper in the call stack, like at the point of the error, or using a less hamfisty try/catch implementation.
Try::Tiny is just a very thin wrapper around eval. What that means is, it basically evals the try sub and then runs the catch sub if $@ is truthy. By the time the catch sub runs, the try "block" has already returned and the stack frames are gone. Not optimized away -- just gone. The eval's returning has killed the stack frames for what it was eval'ing. All you really have left is the error info in $@.
Below is a trivial example. As you will see, neither bar() nor bletch() are included in the stack trace.
Yeah, because you've exited bar and bletch before getting the stack trace.
Create a $SIG{__DIE__} handler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With