Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if Perl code is being run inside an eval?

Tags:

perl

I've got a module that uses an @INC hook and tries to install missing modules as they are used. I don't want this behaviour to fire inside an eval. My attempt to do this currently is:

return
    if ( ( $caller[3] && $caller[3] =~ m{eval} )
    || ( $caller[1] && $caller[1] =~ m{eval} ) );

That's the result of me messing around with the call stack in some experiments, but it's not catching everything, like this code in HTTP::Tinyish:

sub configure_backend {
    my($self, $backend) = @_;
    unless (exists $configured{$backend}) {
        $configured{$backend} =
          eval { require_module($backend); $backend->configure };
    }
    $configured{$backend};
}

sub require_module {
    local $_ = shift;
    s!::!/!g;
    require "$_.pm";
}

Maybe I just need to traverse every level of the call stack until I hit an eval or run out of levels. Is there a better or easier way for me to figure out whether or not code is being wrapped in an eval without traversing the call stack?


Post mortem on this question:

  • as was suggested by multiple posters, this was basically a bad idea
  • $^S is technically a correct way to do this, but it doesn't let you know if you're inside an eval that was called somewhere higher in the stack
  • using a regex + Carp::longmess() seems to be the most concise way to figure this out
  • knowing if code is running inside an eval may be somewhat helpful for informational purposes, but since this could be happening for many different reasons, it's very hard to infer why it's happening
  • regardless, this was an interesting exercise. i thank all contributors for their helpful input
like image 425
oalders Avatar asked Jul 23 '18 16:07

oalders


2 Answers

Carp::longmess traverses the stack for you in one call, if that makes things easier

return if Carp::longmess =~ m{^\s+eval }m
like image 66
mob Avatar answered Sep 18 '22 10:09

mob


If $^S is true, the code is inside an eval.

sub foo { print $^S }
eval { foo() };  # 1
foo();           # 0
like image 28
Schwern Avatar answered Sep 22 '22 10:09

Schwern