Mailing List Archive

$SIG{__DIE__} (was Re: Over-zealous warnings ignore eval)
On Wed, 30 Aug 1995, Larry Wall wrote:

> : % perl -le 'print "here"; eval q(a "b"); print "there"'
> : here
> : String found where operator expected at (eval 1) line 1, near "a "b""
> : (Do you need to predeclare a?)
> : there
>
> $SIG{__WARN__} was construed as a fix for this, or at least a workaround.
> It's hard to know how best to handle this in the general case. The current
> default is to err on the side of providing too much information rather
> than too little.

That reminds me of something else. I just tried using $SIG{__DIE__}, but
I must say that the behaviour isn't too helpful in my case. It always
appends the line and file info (if no LF.) I was hoping that I could
override this.

Spefically, in working on the POD stuff, it would be great if:

die "L<...> may not contain nested commands";

could be turned by $SIG{__DIE__} into:

die "L<...> may not contain nested commands near line $line of $ARGV.\n";

Unfortunately, it seems that just can't be done right now.

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
>From: Kenneth Albanowski <kjahds@kjahds.com>
>
>That reminds me of something else. I just tried using $SIG{__DIE__}, but
>I must say that the behaviour isn't too helpful in my case. It always
>appends the line and file info (if no LF.) I was hoping that I could
>override this.

You must be missing something. You have to leave the subroutine with a
goto or exit. Assign @_ to a variable, process it in perl, and voila'.

>
>Spefically, in working on the POD stuff, it would be great if:
>
> die "L<...> may not contain nested commands";
>
>could be turned by $SIG{__DIE__} into:
>
> die "L<...> may not contain nested commands near line $line of $ARGV.\n";

your line number is in $. isn't it? Here is what I use:

{
local $SIG{__DIE__} = sub { do_log("VERRRY Bad URL: $uri: @_"); goto RETURN; };
unless ($uri_obj = new URI::URL $uri, $Config->{INCOMING}){
do_log("Bad URL: $uri");
return;
}
}
RETURN: return;

>
>Unfortunately, it seems that just can't be done right now.

I doubt :)

>
>--
>Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
>
>
andreas
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Thu, 31 Aug 1995, Andreas Koenig wrote:

> You must be missing something. You have to leave the subroutine with a
> goto or exit. Assign @_ to a variable, process it in perl, and voila'.

Agreed, it's just that the voila' in question isn't quite the voila' I need.

> > die "L<...> may not contain nested commands near line $line of $ARGV.\n";
>
> your line number is in $. isn't it? Here is what I use:

No, not in this case. I'm reading in paragraphs at a time, and the
defaults aren't of much use.

> {
> local $SIG{__DIE__} = sub { do_log("VERRRY Bad URL: $uri: @_"); goto RETURN; };
> unless ($uri_obj = new URI::URL $uri, $Config->{INCOMING}){
> do_log("Bad URL: $uri");
> return;
> }
> }
> RETURN: return;
>
> >
> >Unfortunately, it seems that just can't be done right now.
>
> I doubt :)

Yes, but you are using "do_log", not die, and you aren't worring about \n.
Here's what I tried:

$SIG{__DIE__} = sub {
die "(nonl) @_ near line $line of $ARGV\n" if substr("@_",-1,1) ne "\n";
die "(withnl) @_";
cancel;
};

die "foo";

This _appears_ to be the obvious way to do this sort of thing. The only
problem is that it doesn't work. The "at $ARGV line $." is tucked onto @_
before you get a say in things.

> >Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
> >
> andreas
>

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
>From: Kenneth Albanowski <kjahds@kjahds.com>
>Yes, but you are using "do_log", not die, and you aren't worring about \n.
>Here's what I tried:
>
>$SIG{__DIE__} = sub {
> die "(nonl) @_ near line $line of $ARGV\n" if substr("@_",-1,1) ne "\n";
> die "(withnl) @_";
> cancel;
>};
>
>die "foo";

Kenneth,

I think I understand what you mean, and I think I have a
solution. Whereas I use $SIG{__DIE__} to workaround the croak()s and
die()s in the LWP library, you try something completely different.

But as you describe the problem, you seem to be free to call whatever
you want in your functions and methods. If you do not call die(), you
do not need to use $SIG{__DIE__}.

Can't your example

>Spefically, in working on the POD stuff, it would be great if:
>
> die "L<...> may not contain nested commands";
>
>could be turned by $SIG{__DIE__} into:
>
> die "L<...> may not contain nested commands near line $line of $ARGV.\n";
>
>Unfortunately, it seems that just can't be done right now.

easily be solved by calling

myerrorhandler("L<...> may not contain nested commands");

instead?

IFF you want to catch a foreign die() and you don't know, if the die()
will come with or without " at filename line nnn." tacked (sp?) on @_,
then you can apply this substitution (messy but correct, I think):

$SIG{__DIE__}=sub {
# tested with very weird filenames with newlines and metacharacters embedded
my($message) = @_;
print "message [$message]\n";
@caller=caller;
$message =~ s/ at \Q$caller[1]\E line $caller[2]\.\n//s;
print "message [$message]\n";
die "bar";
};

I agree, that this is not the most elegant approach. Basically I undo
what the die() code did. But I think, it does what you want. Do you
have an imagination how you would like the $SIG{__DIE__} interface?
Maybe you would prefer that the $SIG{__DIE__} subroutine is called
with 3 arguments instead of one?

$SIG{__DIE__} = sub {
my($message,$file,$line) = @_;
}

????

>Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)

andreas
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Fri, 1 Sep 1995, Andreas Koenig wrote:

> Kenneth,
>
> I think I understand what you mean, and I think I have a
> solution. Whereas I use $SIG{__DIE__} to workaround the croak()s and
> die()s in the LWP library, you try something completely different.

Quite right.

> Can't your example
> [...]
> easily be solved by calling
>
> myerrorhandler("L<...> may not contain nested commands");
>
> instead?

Yes, it can, but to my mind this is discarding one of the points of having
$SIG{__DIE__} in the first place. die() normally knows about line numbers
and files, and will automatically append that information. In the code
environment I'm working in, files are loaded by paragraphs, and thus the
defaults really doesn't work quite well enough. I'd much prefer to use a
real die(). (Not to mention the fact that with die(), warn(), croak(),
carp(), and whatever other warning mechanisms there are, it's much easier
to remember just die(). ;-)

> IFF you want to catch a foreign die() and you don't know, if the die()
> will come with or without " at filename line nnn." tacked (sp?) on @_,
> then you can apply this substitution (messy but correct, I think):
>
> $SIG{__DIE__}=sub {
> # tested with very weird filenames with newlines and metacharacters embedded
> my($message) = @_;
> print "message [$message]\n";
> @caller=caller;
> $message =~ s/ at \Q$caller[1]\E line $caller[2]\.\n//s;
> print "message [$message]\n";
> die "bar";
> };

Yes, that would do it. And yes, this isn't very elegant.

> I agree, that this is not the most elegant approach. Basically I undo
> what the die() code did. But I think, it does what you want. Do you
> have an imagination how you would like the $SIG{__DIE__} interface?

My original idea (back when I suggested $SIG{__DIE__}) was that only an
actual die() would append the " at X line Y." data, and the $SIG{__DIE__}
routine would never see it. Larry took the opposite tack and it gets
appended before $SIG{__DIE__} is invoked.

> Maybe you would prefer that the $SIG{__DIE__} subroutine is called
> with 3 arguments instead of one?
>
> $SIG{__DIE__} = sub {
> my($message,$file,$line) = @_;
> }
>
> ????

I'd say:

$SIG{__DIE__} = sub {
my($message,$append) = @_;
}

where $append is whatever message that die() thought it should append.
Thus, fixing it up becomes simple:

$SIG{__DIE__} = sub {
my($message,$append) = @_;
$append = " near line $line of $ARGV." if $append;
die($message.$append);
}

If $message had a terminal \n, then $append would come in empty, and thus
you wouldn't get the message.

> >Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
>
> andreas

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Just noticed this in Exporter.pm:

sub export {

# First make import warnings look like they're coming from the "use".
local $SIG{__WARN__} = sub {
my $text = shift;
$text =~ s/ at \S*Exporter.pm line \d+.\n//;
local $Carp::CarpLevel = 1; # ignore package calling us too.
Carp::carp($text);
};
....

Seems like this behaviour is just a general nuisance, really.


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: My original idea (back when I suggested $SIG{__DIE__}) was that only an
: actual die() would append the " at X line Y." data, and the $SIG{__DIE__}
: routine would never see it. Larry took the opposite tack and it gets
: appended before $SIG{__DIE__} is invoked.

I thought I'd err on the side of not discarding potentially valuable info.
Apparently I did in fact err on that side... :-)

: > Maybe you would prefer that the $SIG{__DIE__} subroutine is called
: > with 3 arguments instead of one?
: >
: > $SIG{__DIE__} = sub {
: > my($message,$file,$line) = @_;
: > }
: >
: > ????
:
: I'd say:
:
: $SIG{__DIE__} = sub {
: my($message,$append) = @_;
: }
:
: where $append is whatever message that die() thought it should append.

I'd call it "$where", but that's neither here nor there.

: Thus, fixing it up becomes simple:
:
: $SIG{__DIE__} = sub {
: my($message,$append) = @_;
: $append = " near line $line of $ARGV." if $append;
: die($message.$append);
: }
:
: If $message had a terminal \n, then $append would come in empty, and thus
: you wouldn't get the message.

Now's the time to change it if we're gonna. Feel free to send a patch.

As long as you're in there, you might think about the relationship of
nested (via local) pseudo-signal handlers. Then again, you might not... :-)

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> As long as you're in there, you might think about the relationship of
> nested (via local) pseudo-signal handlers. Then again, you might not... :-)

Ug. diagnostics.pm and CGI::ErrorWrap.pm are both $SIG{__WARN__}
and $SIG{__DIE__} users, and they go to silly steps to try to
make this work. it's something of a hassle.

--tom
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Tue, 5 Sep 1995, Tom Christiansen wrote:

> > As long as you're in there, you might think about the relationship of
> > nested (via local) pseudo-signal handlers. Then again, you might not... :-)
>
> Ug. diagnostics.pm and CGI::ErrorWrap.pm are both $SIG{__WARN__}
> and $SIG{__DIE__} users, and they go to silly steps to try to
> make this work. it's something of a hassle.

Mind 'splaining just which bits you don't like? For that matter, care to
explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?

Exactly what behaviour would you prefer.

> --tom

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 6 Sep 1995, Tom Christiansen wrote:

> > Mind 'splaining just which bits you don't like?
>
> i don't like having to keep track of the previous warn/die handler
> when i install a new one in the case that i still want the old
> one to execute.

Well, let's see. Do you want handlers installed before yours to be
executed before or after your handler? What about handlers installed after
yours? Should they have some way of invoking your handler if they want to?

Perhaps we just need to do something like this:

my($oldhandler) = $SIG{__DIE__};
$SIG{__DIE__} = sub {
# do our stuff
if($oldhandler) {
&$oldhandler();
} else {
die; #er, or exit, or however this gets worked out
}
}

Or... perhaps this:

my($oldhandler) = $SIG{__DIE__};
$SIG{__DIE__} = sub {
my($message,$where)=@_;
local($SIG{__DIE__}) = $oldhandler;

# do our stuff

die($message.$where);
}

Or am I going off on the wrong tack?

> > For that matter, care to
> > explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?
>
> repeated imports? redefinition? ok, maybe not. actually, that check
> is in there because i was quite paranoid about (not) ever recursively
> calling myself.

Fair enough. I was thinking the same thing looking through the code.

> --tom

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Tue, 5 Sep 1995, Larry Wall wrote:

> I thought I'd err on the side of not discarding potentially valuable info.
> Apparently I did in fact err on that side... :-)

Well, erring on any side is better then not having it at all ;-)

> : where $append is whatever message that die() thought it should append.
>
> I'd call it "$where", but that's neither here nor there.

Fine.

> Now's the time to change it if we're gonna. Feel free to send a patch.

No patch yet. But some ideas: since die() actually takes a list (not that
I've known anyone to use it) how about keeping it in list form for
__DIE__/__WARN__, but appending on the $where message to the argument
list?

That would give us:

$SIG{__DIE__} = sub {
my($where,@msg) = $_[-1], @_[0..-2];

}

> As long as you're in there, you might think about the relationship of
> nested (via local) pseudo-signal handlers. Then again, you might not... :-)

The above change would give us a noticable benefit, in that the signal
handler could change $SIG{__DIE__}, and then reinvoke die() like:

die(@msg,$ourwhere);

or

die(@msg,"");

thus allowing the nested handler to maintain full control over the error
messages.

Of course, I'm not sure what nested dies() do currently. That might have
to be: &$oldhandler(@msg,$ourwhere) and not die().

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> On Tue, 5 Sep 1995, Tom Christiansen wrote:

> > > As long as you're in there, you might think about the relationship of
> > > nested (via local) pseudo-signal handlers. Then again, you might not... :-)
> >
> > Ug. diagnostics.pm and CGI::ErrorWrap.pm are both $SIG{__WARN__}
> > and $SIG{__DIE__} users, and they go to silly steps to try to
> > make this work. it's something of a hassle.

> Mind 'splaining just which bits you don't like?

i don't like having to keep track of the previous warn/die handler
when i install a new one in the case that i still want the old
one to execute.

> For that matter, care to
> explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?

repeated imports? redefinition? ok, maybe not. actually, that check
is in there because i was quite paranoid about (not) ever recursively
calling myself.

--tom
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> From: Kenneth Albanowski <kjahds@kjahds.com>
>
> On Wed, 6 Sep 1995, Tom Christiansen wrote:
>
> > > Mind 'splaining just which bits you don't like?
> >
> > i don't like having to keep track of the previous warn/die handler
> > when i install a new one in the case that i still want the old
> > one to execute.
>
> Well, let's see. Do you want handlers installed before yours to be
> executed before or after your handler?
> What about handlers installed after yours?

Execute in reverse order. Most recent first.

> Should they have some way of invoking your handler if they want to?
>
Not worth adding anything special for that.

> Perhaps we just need to do something like this:
>
> my($oldhandler) = $SIG{__DIE__};
> $SIG{__DIE__} = sub {
> # do our stuff
> if($oldhandler) {
> &$oldhandler();
> } else {
> die; #er, or exit, or however this gets worked out
> }
> }
>
> Or... perhaps this:
>
> my($oldhandler) = $SIG{__DIE__};
> $SIG{__DIE__} = sub {
> my($message,$where)=@_;
> local($SIG{__DIE__}) = $oldhandler;
> # do our stuff
> die($message.$where);
> }
>
> Or am I going off on the wrong tack?
>
> > > For that matter, care to
> > > explain how $oldwarn in warn_trap could possibly be set to \&warn_trap?
> >
> > repeated imports? redefinition? ok, maybe not. actually, that check
> > is in there because i was quite paranoid about (not) ever recursively
> > calling myself.
>
> Fair enough. I was thinking the same thing looking through the code.
>
I'd like to see something like this:

push @$SIG{__DIE__}, sub {
return 0 unless m/my msg text/; # not one I want to handle
...handle error here...
};

E.g.,
$SIG{__DIE__} is an array of handlers.
Each handler gets called in turn until one returns true.
If $SIG{__DIE__} is not an array ref act as now (compatibility).

Or...
Make local($SIG{__DIE__}) 'magical' so that the previous
handlers get called (in reverse order till one returns true).

Tim.
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
> >
> > Well, let's see. Do you want handlers installed before yours to be
> > executed before or after your handler?
> > What about handlers installed after yours?

> Execute in reverse order. Most recent first.

> > Should they have some way of invoking your handler if they want to?
> >
> Not worth adding anything special for that.

> > Perhaps we just need to do something like this:
> >
> > my($oldhandler) = $SIG{__DIE__};
> > $SIG{__DIE__} = sub {
> > # do our stuff
> > if($oldhandler) {
> > &$oldhandler();
> > } else {
> > die; #er, or exit, or however this gets worked out
> > }
> > }
> >

that's interesting stuff, and it might well be worth doing.

--tom
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: > > Well, let's see. Do you want handlers installed before yours to be
: > > executed before or after your handler?
: > > What about handlers installed after yours?
:
: > Execute in reverse order. Most recent first.
:
: > > Should they have some way of invoking your handler if they want to?
: > >
: > Not worth adding anything special for that.
:
: > > Perhaps we just need to do something like this:
: > >
: > > my($oldhandler) = $SIG{__DIE__};
: > > $SIG{__DIE__} = sub {
: > > # do our stuff
: > > if($oldhandler) {
: > > &$oldhandler();
: > > } else {
: > > die; #er, or exit, or however this gets worked out
: > > }
: > > }
: > >
:
: that's interesting stuff, and it might well be worth doing.

The code above is, of course, incorrect, since it's passing no argument
(or arguments) to &$oldhandler(). We need to think about this more, and
whether we really want to reinvent the eval {} mechanism poorly.

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Wed, 6 Sep 1995, Larry Wall wrote:

> The code above is, of course, incorrect, since it's passing no argument
> (or arguments) to &$oldhandler(). We need to think about this more, and
> whether we really want to reinvent the eval {} mechanism poorly.

Of course. Code of the top of the head does that sometimes.

I think using a closure is the right action here, as it's cleaner then
$ubstitution, and the __WARN__ handler should be kept dynamic, not
compiled in as a eval {} does. Try this one on for size:

package WarnHandler;

sub new {
my($this,$sub) = @_;
my($oldhandler) = $SIG{__WARN__};

return sub {
my($where,@msg);
if(@_==1) {
# Disect original warning
if ($_[0] =~ /^(.*) (at \S+ line \d+.\n)$/) {
$where=$2;
@msg=($1);
} else {
@msg=$_[0];
$where="";
}
} else {
# Pass along previously disected warning
$where = shift @_;
@msg = @_;
}
#print "w=$where, m=",join("|",@msg),"\n";
{
# Make sure we can't recurse
local($SIG{__WARN__})="";
my(@ret)=&$sub($where,@msg);
($where,@msg)=@ret;
} continue {
#print "w=$where, m=",join("+",@msg),"\n";
if( $oldhandler ) {
&$oldhandler($where,@msg);
} else {
warn(@msg,($where?" ":""),$where);
}
}
};
}

package main;


local($SIG{__WARN__}) = new WarnHandler sub { print join("|","",@_,""),"\n"; next };

local($SIG{__WARN__}) = new WarnHandler sub {
my($where,@msg)=@_;
print "Dear, dear, dear. ",join("",@msg)," $where\n";
warn "test warning";
next;
};

local($SIG{__WARN__}) = new WarnHandler sub {
my($where,@msg)=@_;
chop $where;
return "({$where})\n",@msg;
};


warn "Invalid something or other";

__END__


This one has some interesting capabilities. It fixes up the $where
problem, by brute force, and it lets warn handlers have full control over
the future: you be the C<last> handler or go to the C<next> one, or
C<return> a set of parameters to be used by other handlers. I think this
takes care of all the important stuff.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
[Proposal for generating warning handlers elided]

> return sub {
> my($where,@msg);

I'm a bit slow catching up on this thread, but before we get too far along, I'd
like to put in a word of support for Larry Wall's notion that warning handlers
return $file,$line for the current warning as separate items. That'd make it
easier to manipulate the offending source code in a complex handler, and the
default behavior would just involve creating the string "at $file line $line".

I realize that that under Kenneth Albanowski's scheme, getting at the location
of the error is just a matter of a pattern match, but it seems cleaner to
construct the string only when one needs it. Either option will require
shifting the location information up from mess() to warn(), croak(), or die();
it's just a matter of one string vs. a string and a number.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Whoops, mail to p5p failed. Here's a repost:

package WarnHandler;

sub new {
my($this,$sub) = @_;
my($oldhandler) = $SIG{__WARN__};

return sub {
my($file,$line,@msg);
if(@_==1) {
# Disect original warning
if ($_[0] =~ /^(.*) at (\S+) line (\d+).\n$/) {
$file=$2;
$line=$3;
@msg=($1);
} else {
@msg=$_[0];
$file="";
$line="";
}
} else {
# Pass along previously disected warning
$file = shift @_;
$line = shift @_;
@msg = @_;
}
{
# Make sure we can't recurse
local($SIG{__WARN__})="";
my(@ret)=&$sub($file,$line,@msg);
($file,$line,@msg)=@ret;
} continue {
if( $oldhandler ) {
&$oldhandler($file,$line,@msg);
} else {
warn(@msg,($file?" at $file line $line.":""));
}
}
};
}

package main;


local($SIG{__WARN__}) = new WarnHandler sub { print join("|","",@_,""),"\n"; next };

local($SIG{__WARN__}) = new WarnHandler sub {
my($file,$line,@msg)=@_;
print "Dear, dear, dear. ",join("",@msg),"\n";

warn "test warning"; # trigger unhandled warning

next;
};

local($SIG{__WARN__}) = new WarnHandler sub {
my($file,$line,@msg)=@_;
#demo a handler that just changes the data
return "","",@msg," at line $line of $file\n";
};


warn "Invalid something or other";


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
: [Proposal for generating warning handlers elided]
:
: > return sub {
: > my($where,@msg);
:
: I'm a bit slow catching up on this thread, but before we get too far along, I'd
: like to put in a word of support for Larry Wall's notion that warning handlers
: return $file,$line for the current warning as separate items. That'd make it
: easier to manipulate the offending source code in a complex handler, and the
: default behavior would just involve creating the string "at $file line $line".
:
: I realize that that under Kenneth Albanowski's scheme, getting at the location
: of the error is just a matter of a pattern match, but it seems cleaner to
: construct the string only when one needs it. Either option will require
: shifting the location information up from mess() to warn(), croak(), or die();
: it's just a matter of one string vs. a string and a number.

Uh, the attributions are getting fouled up here. Andreas Koenig
originally proposed the 3 arg form, I believe. And Kenneth doesn't
*want* to do pattern matching--that's what brought this all on in the
first place... :-)

On the other hand, I don't see how you can get out of pattern matching if
the user said something like

die "oops at $0 line " . (__LINE__ + $evalbase) . "\n";

Larry
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Thu, 7 Sep 1995, Larry Wall wrote:

> Uh, the attributions are getting fouled up here. Andreas Koenig
> originally proposed the 3 arg form, I believe. And Kenneth doesn't
> *want* to do pattern matching--that's what brought this all on in the
> first place... :-)
>
> On the other hand, I don't see how you can get out of pattern matching if
> the user said something like
>
> die "oops at $0 line " . (__LINE__ + $evalbase) . "\n";

Agreed. I actually don't mind the pattern matching in the WarnHandler
style handler, since it takes care of separating out the parts for you.

> Larry

--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Larry Wall wrote:
> Charles Bailey wrote:
> : I'm a bit slow catching up on this thread, but before we get too far along, I'd
> : like to put in a word of support for Larry Wall's notion that warning handlers
> : return $file,$line for the current warning as separate items. That'd make it
> : easier to manipulate the offending source code in a complex handler, and the
> : default behavior would just involve creating the string "at $file line $line".
> :
> : I realize that that under Kenneth Albanowski's scheme, getting at the location
> : of the error is just a matter of a pattern match, but it seems cleaner to
> : construct the string only when one needs it. Either option will require
> : shifting the location information up from mess() to warn(), croak(), or die();
> : it's just a matter of one string vs. a string and a number.
>
> Uh, the attributions are getting fouled up here. Andreas Koenig
> originally proposed the 3 arg form, I believe. And Kenneth doesn't
> *want* to do pattern matching--that's what brought this all on in the
> first place... :-)

Wups. I apologize for tangling the thread.

> On the other hand, I don't see how you can get out of pattern matching if
> the user said something like
>
> die "oops at $0 line " . (__LINE__ + $evalbase) . "\n";

As far as I can see, you can't. I think I'm being unclear about what I'm
suggesting. Let me try again: Ideally, when an exception is thrown, I'd like
to see three data associated with it:
$file - path to the file in which the code that threw the exception was
found. In the case of an eval, this might be one of
o while ($eval_depth) {
$file .= "eval (line $eval_line[$eval_depth--]): ";
}
$file .= " some/where/Over/Rainbow.pm";
This allows one to recognize that the error occurrent in
an eval, but to anchor it in a file somewhere, and to
pull out the file name with a /: (\S+)$/. It'd require
the most internal modifications, of course.
o "some/where/Over/Rainbow.pm"
Gets one directly to the nearest "permanent" point of
reference, but loses information about eval context.
It'd probably require only slightly less in the way of
internal modifications than the previous option.
o "(eval $n)"
Simple, but of minimal utility in tracking down some
persistent reference point for debugging. Requires
no internal modification, beyond pushing the filegv
directly onto the stack instead of wrapping it in
the "at %s line %d" form.
$line - line in $file executing when the exception was thrown. This is
again a problem when the exception occurs inside an eval, but,
expecially in combination with the first option above, I'd be
inclined to make this the line of the "innermost" actual file
(including -e) executing.
$msg - whatever the user passed as an argument to C<warn> or C<die>.

Basically, I'm trying to set out a mechanism by which a handler receives
"reliable" information about the location of an exception, without having
to depend on the way that the user formats the message passed to C<die> or
C<warn>. I see this as an advantage for a few reasons:
o It may make things simpler for handlers with an interest in the
location of the exceptions.
o It provides a uniform way to locate the spot at which the exception
occurred, without requiring everyone who throws an exception to adhere
to a particular convention when formatting message. Of course, handlers
which are aware that $msg is going to come to them in a particular format
are welcome to take advantage of that fact.
o It shifts the process of constructing the "at %s line %d" suffix out to
the default or "last-chance" exception handler, which means that
exceptions which get passed down a line of handlers won't cause a lot
of building and tearing down of strings.

I realize that the details get a bit fuzzy when dealing with nested evals, but
I don't know of any way, absent passing around a stack of "interpreter frames",
to adequately represent the location of an exception buried deep among the
evals.

Well, that's my $0.02, perhaps with a little interest. I hope it's a bit
clearer than my first try.

Regards,
Charles Bailey bailey@genetics.upenn.edu
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Charles Bailey writes:
> I realize that the details get a bit fuzzy when dealing with nested evals, but
> I don't know of any way, absent passing around a stack of "interpreter frames",
> to adequately represent the location of an exception buried deep among the
> evals.
>

I do not think that nested evals are of any problem, since at least
this info is recoverable now.

As always on this list, I repeat the same again: the most complicated
problem is subs defined inside eval. I think that something like

use debug -g;

that will preserve the text of eval inside the CV is needed here.

Ilya
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
On Fri, 8 Sep 1995, Charles Bailey wrote:

> Well, that's my $0.02, perhaps with a little interest. I hope it's a bit
> clearer than my first try.

Thanks, this is some excellent material. First of all, how do you feel
about _not_ changing Perl itself, and using a pre-handler that massages
(or actually creates) the trace data in the format that you want? That
seems to be relatively easy to do using a syntax like:

local($SIG{__DIE__}) = new DieHandler sub {
my($file,$line,@msg) = @_;
#...
last #handler
};

If this seems reasonable, then the steps that the DieHandler takes seem
fairly simple:

1. trace the caller tree, using something roughly like:

$i=0;
while (@a= caller($i++)) {
print "\n",join("|",@a),"\n";
$sub = $a[3];
$line = $a[2];
$file = $a[1];
if( $file =~ /^\(eval/ ) {
$oline = (caller($i))[2];
print "the eval at line $oline of ";
} else {
print $file,"\n";
last;
}
}

This gives the full location, in any format you'd like, within what
caller() can provide. (Which, as Ilya has mentioned, is everything but
the contents of subs defined in evals. Also, in a quick test, anonymous
subs may need a bit more work to catch properly.)

Note that in this format, the messages is reversed into "line $l of $f" to
get it to form decent English. Nothing major there.


2. Take what die() provides to a __DIE__ handler, and "digest" it.
Specifically, if it ends in " at \S+ line \d+.\n", then just chop it off,
and make sure there is no newline at the end.


3. Return an closure that calls the provided sub/closure with three
arguments: $file (the trace above), $line (the innermost line number),
and @msg (or $msg, if you prefer) which is what the __DIE__ handler gets.

Something similar to this seems to work fine:

sub NewDieHandler {
my($sub) = @_;
my($oldhandler)=$SIG{__DIE__};
return sub {
my($file,$line,$msg);
if(@_==1) { #__DIE__ call
#digest & trace
} else {
($file,$line,$msg)=@_;
}
{
&$sub();
} continue {
&$oldhandler($file,$line,$msg) if $oldhandler;
}

}
}


4. Install a default handler as part of this mechanism consisting of:

sub {
my($file,$line,$msg) = @_;
if( substr($msg,-1,1) eq "\n" ) {
die $msg;
} else {
die "$msg at line $line of $file.\n";
}
}


Note that a more robust WarnHandler could let the sub (by returning
different values) change the $file, $line and/or $msg that the next
handler in the chain sees.

So (after all that), does this look like it will do all that you are
looking for?

> Regards,
> Charles Bailey bailey@genetics.upenn.edu


--
Kenneth Albanowski (kjahds@kjahds.com, CIS: 70705,126)
Re: $SIG{__DIE__} (was Re: Over-zealous warnings ignore eval) [ In reply to ]
Kenneth Albanowski wrote:
>On Fri, 8 Sep 1995, Charles Bailey wrote:
>
>> Well, that's my $0.02, perhaps with a little interest. I hope it's a bit
>> clearer than my first try.
>
>Thanks, this is some excellent material. First of all, how do you feel
>about _not_ changing Perl itself, and using a pre-handler that massages
>(or actually creates) the trace data in the format that you want? That

Sounds fine -- the only reason I suggested changing the way Perl sets up the
error messages is to improve efficiency. Coding the initial pass in Perl
shouldn't be a problem; if exception-driven code in the future needs better
performance, we can address the issue then.


> 1. trace the caller tree, using something roughly like:
>
> $i=0;
> while (@a= caller($i++)) {
> print "\n",join("|",@a),"\n";
> $sub = $a[3];
> $line = $a[2];
> $file = $a[1];
> if( $file =~ /^\(eval/ ) {
> $oline = (caller($i))[2];
> print "the eval at line $oline of ";
> } else {
> print $file,"\n";
> last;
> }
> }
>
>This gives the full location, in any format you'd like, within what
>caller() can provide. (Which, as Ilya has mentioned, is everything but
>the contents of subs defined in evals. Also, in a quick test, anonymous
>subs may need a bit more work to catch properly.)
>
> [text deleted]
>
> 3. Return an closure that calls the provided sub/closure with three
>arguments: $file (the trace above), $line (the innermost line number),
>and @msg (or $msg, if you prefer) which is what the __DIE__ handler gets.

Sounds OK. I've no preference between $msg and @msg. IWBNI if the format of
$file made it easy to pick out the spec for the file in which $line is located.
Perhaps it could be quoted somehow, or, in the format you use above, /(\S+)\n/
should do the trick.

>Something similar to this seems to work fine:
>
> sub NewDieHandler {
> my($sub) = @_;
> my($oldhandler)=$SIG{__DIE__};
> return sub {
> my($file,$line,$msg);
> if(@_==1) { #__DIE__ call
> #digest & trace
> } else {
> ($file,$line,$msg)=@_;
> }
> {
> &$sub();
> } continue {
> &$oldhandler($file,$line,$msg) if $oldhandler;
> }
>
> }
> }

Sounds fine, if the local($SIG{__DIE__}) is used to handle scoping. We're
still left with ways to deal with concurrent exceptions (e.g. what effect do we
want if &$sub generates an exception?). For now, it may be best to wrap &$sub
and &$oldhandler in an eval, to insure that any exceptions it generates aren't
passed to $SIG{__DIE__}, and around and around . . .

> 4. Install a default handler as part of this mechanism consisting of:
>
> sub {
> my($file,$line,$msg) = @_;
> if( substr($msg,-1,1) eq "\n" ) {
> die $msg;
> } else {
> die "$msg at line $line of $file.\n";
> }
> }

Again, the C<die> in the sub can't call $SIG{__DIE__}, or it'll loop. Do we
have to say
print STDERR $msg;
exit $!; # or some analog which mimics current behavior
explicitly?

>Note that a more robust WarnHandler could let the sub (by returning
>different values) change the $file, $line and/or $msg that the next
>handler in the chain sees.
>
>So (after all that), does this look like it will do all that you are
>looking for?

Seems like a good first cut. I'm sure I'm missing something that I'll realize
only when it comes up in a concrete example, but then, that's what v1.0 is for.

Thanks.

Regards,
Charles Bailey bailey@genetics.upenn.edu

1 2  View All