Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > BEGIN, eval and $^S

Reply
Thread Tools

BEGIN, eval and $^S

 
 
Adrien BARREAU
Guest
Posts: n/a
 
      06-05-2013
Hi all.

If I run that piece of code:

=====
#!/usr/bin/perl

use strict;
use warnings;


BEGIN {
$SIG{ __DIE__ } = sub { print "Defined\n" if defined $^S; print
($^S ? "True\n" : "False\n"); };
eval { die };
}

print "Done\n";
=====

It prints:
False
Done

Well, that, I understand.


If I change eval { die } to eval 'die', it prints:
Defined
True
Done

Which I don't get.

My only guess: since eval "" is described as a "little Perl program",
$^S is set to 1 because it refers to the "running" part of the eval,
after it has been successfully parsed. But, my "main" program is in
compilation time, so it seems strange.


Did I missed something about all that in the documentation?

Adrien.
 
Reply With Quote
 
 
 
 
Adrien BARREAU
Guest
Posts: n/a
 
      06-05-2013
On 06/05/2013 04:20 PM, Ben Morrow wrote:
>
> Quoth Adrien BARREAU<(E-Mail Removed)>:
>> Hi all.
>>
>> If I run that piece of code:
>>

[ code skipped ]
>>
>> It prints:
>> False
>> Done
>>
>> Well, that, I understand.

>
> Hmm, well, that's the one that doesn't quite make sense to me. Perl
> isn't parsing that BEGIN block,


Aren't BEGIN block resolved during compilation phase?
I mean:

$ echo 'BEGIN { print "hello world\n" }' | perl -c -
hello world
- syntax OK


> it's running it


I can not say otherwise, but it's what you called
'running-at-compile-time', and I thought that "compile-time" won.

, so I would expect $^S
> to be true. (Defined because we're running code, true because we're
> inside an eval{} so exceptions are being caught.)
>
>> If I change eval { die } to eval 'die', it prints:
>> Defined
>> True
>> Done
>>
>> Which I don't get.
>>
>> My only guess: since eval "" is described as a "little Perl program",
>> $^S is set to 1 because it refers to the "running" part of the eval,
>> after it has been successfully parsed. But, my "main" program is in
>> compilation time, so it seems strange.

>
> Yes, that's basically right. Not entirely right, since that would mean
> the first example should have $^S true as well,


That's precisely what troubles me .

> but I suspect that's an
> inconsistency or an accident of some kind.
>
> You can have as many layers of BEGIN{}/eval"" as you like, each invoking
> a new level of running-at-compile-time or compiling-at-runtime. I think
> this covers all the important cases:
>

[ skipped code ]
>
> The BEGIN entries don't entirely make sense to me: I would have said,
> before trying it, that you could only get $^S=undef during a __DIE__
> handler handling an exception from a syntax error. That's certainly what
> the documentation implies, not to mention the blue Camel.


Your exemple is really interesting, though I don't get understand
everything either.

>
> If you have 5.14 you can use ${^GLOBAL_PHASE} to get the 'main'
> interpreter state. On earlier perls you can use Devel::GlobalPhase to
> emulate the core variable.


I can not use one of those, I'll have to find something else (but I'll
remember that module, didn't knew it).

>
>> Did I missed something about all that in the documentation?

>
> Yes, you missed the bit in perlvar that says 'don't use $SIG{__DIE__} or
> $^S' . What are you actually trying to do here? There's probably an
> easier way to do it.


I do agree with that, but I have to deal with existing stuff that has to
stay. So I'm trying to fix insidious issues in it.

Adrien.
 
Reply With Quote
 
 
 
 
Adrien BARREAU
Guest
Posts: n/a
 
      06-06-2013
[skip]

> This is really where I started my reasoning. The English.pm name of $^S
> is $EXCEPTIONS_BEING_CAUGHT, and that is what it was intended for: to
> tell you, in a __DIE__ handler, whether the exception you have just
> intercepted was going to be fatal or not. Having $^S be undefined in
> eval{}-in-BEGIN rather defeats that purpose, since in that case
> exceptions most definitely are being caught, yet $^S is false.
>
> It is probably possible to get a reliable indication of this using
> caller: running up the call stack looking for a sub called "(eval)" will
> tell you if you are inside some type of eval; some of the other elements
> returned by caller will tell you what sort of eval (require/use,
> eval-string, eval-block) you're dealing with. If you try this you need
> to be aware that BEGIN blocks (and other magic blocks like DESTROY and
> (I think) tie magic) are always wrapped in an implicit eval{}.


As far as you know, is there any doc about what triggers "implicit eval{}"s?

[skip]

>>
>> I do agree with that, but I have to deal with existing stuff that has to
>> stay. So I'm trying to fix insidious issues in it.

>
> So, explain . There might be a better answer than fighting with
> __DIE__ and $^S.
>


Well, at first, it is work-related, so I am not that free.

The code that uses to check $^S in a __DIE__ signal is a custom Logger
(no link to anythin in CPAN).
It has to catch when a die occurs in order to run some stuff (some dumps
of our environment, CGI related stuff if run in that context, etc).

So basically: catch, do stuff, rethrow.
Rethrow basic idea: if ($eval) { return } else { exit -1 }
(so it is that "if ($eval)" that made me start that thread).

So, it doesn't try to achieve something with that __DIE__ signal, it
just have to run stuff if a die occurs.
I doubt I can do that in a relaly different way. But I'd love to get
ideas if you have some . "Rewrite it" or "use CPAN stuff instead" are
not available options, sadly.


Adrien.
 
Reply With Quote
 
Adrien BARREAU
Guest
Posts: n/a
 
      06-06-2013

>
> Anything calling call_sv with G_EVAL. I don't think there's any
> comprehensive list of Perl constructions, but essentially anything
> called implicitly by perl. So, signal handlers, BEGIN/END/INIT/CHECK/
> UNITCHECK, source filter subs, PROPAGATE methods on exception objects,
> DESTROY methods, overloaded constant handlers. Interestingly it seems I
> was wrong about tie magic: these methods are called without an eval,
> presumably because the call is entirely within the normal control flow.
>
> Of course, the point is that exceptions are actually being caught in all
> these cases. Some of them (signal handlers) will rethrow anything they
> catch; some (BEGIN) will abort the current compilation unit, and some
> (INIT) will abort the whole program.


Interesting, thanks .
For now, I not fluent in perlguts stuff, but I'll take a look to the C
API to better understand that.

>
>>>> I do agree with that, but I have to deal with existing stuff that has to
>>>> stay. So I'm trying to fix insidious issues in it.
>>>
>>> So, explain . There might be a better answer than fighting with
>>> __DIE__ and $^S.
>>>

>>
>> Well, at first, it is work-related, so I am not that free.
>>
>> The code that uses to check $^S in a __DIE__ signal is a custom Logger
>> (no link to anythin in CPAN).
>> It has to catch when a die occurs in order to run some stuff (some dumps
>> of our environment, CGI related stuff if run in that context, etc).
>>
>> So basically: catch, do stuff, rethrow.
>> Rethrow basic idea: if ($eval) { return } else { exit -1 }
>> (so it is that "if ($eval)" that made me start that thread).
>>
>> So, it doesn't try to achieve something with that __DIE__ signal, it
>> just have to run stuff if a die occurs.
>> I doubt I can do that in a relaly different way. But I'd love to get
>> ideas if you have some . "Rewrite it" or "use CPAN stuff instead" are
>> not available options, sadly.

>
> Have you considered the obvious option: wrapping the code in a top-level
> eval? The huge advantage of that is that if the exception is caught and
> handled along the way you don't ever get as far as your top-level
> handler. The most important disadvantage is that you can't get a stack
> trace (or any other information about the immediate environment when the
> exception was thrown), since the stack's been unwound, but there are
> other ways of doing that.
>
> The cleanest is to write an exception class that takes a stack trace
> when it's created, and make sure you only throw exceptions of that
> class. If you already have an exception class you can obviously modify
> it to do this fairly easily; Devel::StackTrace will give you a decent
> realisation of a stack trace.
>
> If you can't do that you could use a CORE::GLOBAL::die override to stuff
> appropriate information into globals and hand the exception back to
> CORE::die to throw normally. Then you can pull the information out again
> in your top-level handler, but *only* if the exception actually ends up
> getting that far.
>
> If for some reason you don't want to wrap the program in eval, you could
> install an END block instead. END blocks are called before a top-level
> exception exits, and they are called with $? == 255 since that is the
> exit code perl is going to use. This is rather less reliable that an
> eval, though, and there isn't any way of recovering and deciding not to
> exit after all, so it's something of a last resort. (Of course, if
> you're interesting in 'logging stuff', you may well want to log non-zero
> exits in any case.)
>
> The point here is to avoid trying to predict the future: it's extremely
> difficult to guess whether a given exception will end up being fatal or
> not, especially given that even if it is caught it might be rethrown, so
> rather than guess just have the 'inner handler' stash the information
> the 'outer handler' will need to do the proper reporting.


Once again, I fully agree with you, but I can not something else than
predicting the future.

That logger is a core module to us, so it is used in thousands of
scripts: wrapping all scripts in eval{}s can not be done, neither
changing all uses of die to use an exception class or overridding
CORE::GLOBAL::die (because I can not do that in all scripts so nothing
will ever ensure me that it is loaded).
END{} stuff is great, but as you said, only for logging purposes.

I'll, of course, keep all that in mind if big changes have to be done
one day.


Adrien.
 
Reply With Quote
 
Adrien BARREAU
Guest
Posts: n/a
 
      06-06-2013
On 06/06/2013 03:03 PM, Ben Morrow wrote:
>
> Quoth Adrien BARREAU<(E-Mail Removed)>:
>>
>> That logger is a core module to us, so it is used in thousands of
>> scripts: wrapping all scripts in eval{}s can not be done, neither
>> changing all uses of die to use an exception class or overridding
>> CORE::GLOBAL::die (because I can not do that in all scripts so nothing
>> will ever ensure me that it is loaded).

>
> And you really can't arrange to call these scripts through a wrapper
> something like this?
>
> #!/usr/bin/perl
>
> my @stack;
> *CORE::GLOBAL::die = sub {
> @stack = ();
> while (my @frame = caller @stack) {
> push @stack, \@frame;
> }
> # or just save away Carp::longmess, or whatever
> };
>
> my $script = shift @ARGV;
> # do is a form of string eval, so it catches exceptions
> unless (do $script) {
> # emit logs based on $@, @stack and other information
> }
>
> ISTM all that should take is a minor adjustment to the webserver
> configuration, or something like that, but I suppose the situation might
> be more complicated than that.
>


That gives me some ideas of things I can try, but I can do something
like that, no.
The main thing is that I have to cover *every* ways the issue can
appear, and I'll never be able to do that by adding something. I can
only do changes in existing things, "paths" that are always used and
will stay.

Thanks for your answers Ben .

Adrien.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
to eval or not to eval? Marc Girod Perl Misc 2 04-19-2011 01:13 PM
eval('07') works, eval('08') fails, why? Alex van der Spek Python 6 01-08-2009 08:24 PM
Different behavior between eval "07" and eval "08" Liang Wang Perl Misc 8 02-02-2008 08:31 PM
DataBinder.Eval and Eval. craigkenisston@hotmail.com ASP .Net 1 06-16-2006 05:33 PM
DataBinder.Eval for an object's property property... like Eval(Container.DataItem,"Version.Major") Eric Newton ASP .Net 3 04-04-2005 10:11 PM



Advertisments