Home > Archive > Tcl > June 2006 > Subst'ed ::errorInfo
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Subst'ed ::errorInfo
|
|
|
| Hi,
I'd like to know the current answer the c.l.t community gives to people
frustrated by:
domain error: argument not in valid range
while executing
"expr {sqrt($x)+sqrt($y)+sqrt($z)+sqrt($t)}"
(procedure "f" line 2)
invoked from within
"f $x $y $z $t"
...
The text above is extracted from ::errorInfo, which is mostly
interested in program text (line numbers and verbatim source excerpts).
Instead, the seasoned programmer is mostly concerned with bugs that
happen in hard-to-reproduce conditions, with some improbable valuation
of his data (guess the offending x,y,z, or t above)... To him,
replaying with instrumented code is rarely an option !
One idea would be to define another special variable, say ::errorStack,
holding the backwards-built list of [info level]'s in the exception's
context. IOW, ::errorStack would hold a list of the *values* of all the
commands and arguments on the stack at the time the error bursts. In
the above example, (giving one list item per line for readability):
expr {sqrt($x)+sqrt($y)+sqrt($z)+sqrt($t)}
f 2 -1 2 2
which immediately identifies the $y as the culprit. Cool, eh ?
One may wonder about the performance hit of adding such a mechanism to
the existing stack-unwinding machinery. I think it is rather low
compared to what's already done for ::errorInfo. Indeed, ::errorInfo is
a concatenation at the string level of various bits. While ::errorStack
would simply be constructed by the much more efficient (C-level)
lappend.
One may also wonder about the memory footprint. I think it is very
limited too: Granted, storing a reference to all [info levels] bumps
their refcounts, and thus keeps some values alive longer than before
while climbing back to the next [catch]. However, the variable
::errorStack could be immediately reset as soon as the next Tcl-level
evaluation completes (hence to use it you must start with something
like "set x $::errorStack") . This way, for all existing Tcl code the
impact of ::errorStack is negligible.
And finally, such a feature could be disabled by default, and enabled
by some config variable just like ::tcl_traceExec enables execution
tracing.
Reactions ?
-Alex
PS: Eons ago I discussed this topic here with several of you, the one
showing most interest being Miguel Sofer. But I'm not aware of any
visible sequel...
| |
| Don Porter 2006-06-24, 8:23 am |
| Alex wrote:
> I'd like to know the current answer the c.l.t community gives to people
> frustrated by:
>
> domain error: argument not in valid range
> while executing
> "expr {sqrt($x)+sqrt($y)+sqrt($z)+sqrt($t)}"
[expr] error messages are hideously bad..
In Tcl 8.5, [expr] is receiving a major rewrite. Some things done
include bignum support and user-defined functions at the Tcl
script level.
Some things left to do are error message cleanup. (If you're
a source code diving type, you may notice some "TODO"s sprinkled
here and there.)
Not a great answer, but it's what I've got to offer.
I'm an anti-fan of Yet Another Global Variable as a proposed solution.
If we can't get a good enough answer building on what's already there,
then add more information as a new return option, not a new global.
--
| Don Porter Mathematical and Computational Sciences Division |
| donald.porter@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|_______________________________________
_______________________________|
| |
| Arjen Markus 2006-06-24, 8:23 am |
|
Alex schreef:
> Hi,
>
> I'd like to know the current answer the c.l.t community gives to people
> frustrated by:
>
> domain error: argument not in valid range
> while executing
> "expr {sqrt($x)+sqrt($y)+sqrt($z)+sqrt($t)}"
> (procedure "f" line 2)
> invoked from within
> "f $x $y $z $t"
>
.....
>
> And finally, such a feature could be disabled by default, and enabled
> by some config variable just like ::tcl_traceExec enables execution
> tracing.
>
> Reactions ?
>
While this may seem attractive at first, there will be major problems
implementing this:
expr {sqrt($x*$x-$y*$y)}
may fail for many reasons:
- $x*$x may be floating-point values too large to represent
- The same goes for $y*$y
- $y may be larger than $x, so that sqrt(negative number) results
- variables x or y may not even have values or values that can not be
interpreted
as numbers (that would not cause a domain error, of course)
- $x or $y may be _integers_ that are so large that the square becomes
negative
That one would have me puzzled for a long time :)
How would you indicate the culprit in any reasonable way?
Regards,
Arjen
| |
|
|
Don Porter wrote:
> Alex wrote:
>
> [expr] error messages are hideously bad..
[expr] was just an example. While I agree with your remark ;-) , it
doesn't address the more general problem: you have a stack of 13 levels
of Tcl procs, and you're just wondering what was the value passed as
argument 4 of level 7...
> I'm an anti-fan of Yet Another Global Variable as a proposed solution.
> If we can't get a good enough answer building on what's already there,
> then add more information as a new return option, not a new global.
*That*'s interesting !!!
I really don't care whether it's a global or something else, I'm just
interested in solving the initial problem. Can you elaborate on how you
would do it a s a return option ?
-Alex
| |
|
|
Arjen Markus wrote:
> Alex schreef:
>
> ....
>
> While this may seem attractive at first, there will be major problems
> implementing this:
>
> expr {sqrt($x*$x-$y*$y)}
>
> may fail for many reasons:
> - $x*$x may be floating-point values too large to represent
> - The same goes for $y*$y
> - $y may be larger than $x, so that sqrt(negative number) results
> - variables x or y may not even have values or values that can not be
> interpreted
> as numbers (that would not cause a domain error, of course)
> - $x or $y may be _integers_ that are so large that the square becomes
> negative
> That one would have me puzzled for a long time :)
>
> How would you indicate the culprit in any reasonable way?
Sorry, but [expr] was just an example, and obviously it didn't help
clarify :-)
In my example, the point is that I get the actual value of arguments to
function f, on which I can calmly compute by hand whatever math
function is implied in later calculations.
-Alex
| |
| suchenwi 2006-06-24, 8:23 am |
| My simpleton solution to such problems is:
(1) Locate the command that threw the error;
(2) add the command "puts x=$x,y=$y,z=$z,..." in front of it
:D
| |
| Ralf Fassel 2006-06-24, 8:23 am |
| * "Alex" <alexandre.ferrieux@gmail.com>
| you have a stack of 13 levels of Tcl procs, and you're just
| wondering what was the value passed as argument 4 of level 7...
'info level' comes handy here, though it's not as useful as walking up
and down the stack in a 'real' debugger.
proc foo {args} {
set i [info level]
while {$i > 0} {
puts "level $i: [info level $i]"
incr i -1
}
}
proc bar {arg1 arg2} {
foo $arg1 $arg2
}
foo 1 2 3
=>
level 1: foo 1 2 3
bar 1 {2 2}
=>
level 2: foo 1 {2 2}
level 1: bar 1 {2 2}
HTH
R'
| |
| Alan Anderson 2006-06-24, 8:23 am |
| > > > domain error: argument not in valid range
"Alex" <alexandre.ferrieux@gmail.com> wrote:
[color=darkred]
> [expr] was just an example.
It seems to me that [expr] is specifically to blame. The trouble is
with the special syntax and "little language", mostly due to the fact
that [expr] does its own parsing and variable substitution outside the
rules of the [en|do]decalogue.
> While I agree with your remark ;-) , it
> doesn't address the more general problem: you have a stack of 13 levels
> of Tcl procs, and you're just wondering what was the value passed as
> argument 4 of level 7...
I don't think that's a problem in general. The only time things get
cryptic is when variable substitution doesn't take place normally.
| |
| Arjen Markus 2006-06-24, 8:23 am |
|
Alex schreef:
>
> Sorry, but [expr] was just an example, and obviously it didn't help
> clarify :-)
> In my example, the point is that I get the actual value of arguments to
> function f, on which I can calmly compute by hand whatever math
> function is implied in later calculations.
>
I completely misunderstood :) I thought you wanted a more clever
way to detect what went wrong in an [expr]-statement. But your
idea is much simpler - add the values of the arguments to the
culprit command. Yes, I miss that too at times.
Regards,
Arjen
| |
| MartinLemburg@UGS 2006-06-24, 8:23 am |
| Arjen Markus wrote:
> Alex schreef:
>
>
> I completely misunderstood :) I thought you wanted a more clever
> way to detect what went wrong in an [expr]-statement. But your
> idea is much simpler - add the values of the arguments to the
> culprit command. Yes, I miss that too at times.
>
> Regards,
>
> Arjen
Just of missing this, I wrote my own stack analyser procedure adding
the stack information I need/want to the ::errorCode part of the error
command call.
This procedure returns at the minimum the stack scopes with the called
procedures/commands/aliases/"namespace inscope" calls/etc. and their
arguments - including default values and with tagged "args" argument
values.
If configured, this procedure returns the global, namespace and local
variables known in the addressed scope.
With this stack analyser procedure it was many times very easy to
realize what's going wrong/on.
So I would be glad to have a feature giving me the stack snapshot,
after an error was raised.
And it doesn't matter to me, if it is a global variable like
"::errorStack", or a new return option "catch"able in the "options"
dictionary (tcl 8.5).
Best regards,
Martin Lemburg
UGS - Transforming the Process of Innovation
| |
| Jeff Hobbs 2006-06-24, 8:23 am |
| Alex wrote:
[discussion on dissecting errorInfo]
> One idea would be to define another special variable, say ::errorStack,
> holding the backwards-built list of [info level]'s in the exception's
> context. IOW, ::errorStack would hold a list of the *values* of all the
> commands and arguments on the stack at the time the error bursts. In
> the above example, (giving one list item per line for readability):
>
> expr {sqrt($x)+sqrt($y)+sqrt($z)+sqrt($t)}
> f 2 -1 2 2
>
> which immediately identifies the $y as the culprit. Cool, eh ?
>
> One may wonder about the performance hit of adding such a mechanism to
> the existing stack-unwinding machinery. I think it is rather low
> compared to what's already done for ::errorInfo. Indeed, ::errorInfo is
> a concatenation at the string level of various bits. While ::errorStack
> would simply be constructed by the much more efficient (C-level)
> lappend.
Have you tried running these issues while in tkcon? The tkcon hot
errors feature works to retrofit a similar stack-examining mechanism on
top of errorInfo when errors occur in the console (like while sourcing a
file or invoking a command). It is very helpful in backtracking through
the code and even seeing the exact line of failure.
Jeff
| |
|
|
Jeff Hobbs wrote :
> Alex wrote:
> [discussion on dissecting errorInfo]
Sorry for the self-quote, but again it's not about dissecting
errorInfo, it's all about keeping data which currently are lost during
the stack unwinding process which builds errorInfo.
I'd have *loved* to do this entirely in Tcl by attaching a write trace
to errorInfo itself, however this subtly fails. I filed a bug report on
this years ago, but somebody explained that this failure was a security
*feature*. So it seems it's easier to add the fature directly in C
(just keep an extra reference to an existing list) than to open the
Pandora box of arbitrary Tcl code in error or trace handlers...
[color=darkred]
> Have you tried running these issues while in tkcon? The tkcon hot
> errors feature works to retrofit a similar stack-examining mechanism on
> top of errorInfo when errors occur in the console (like while sourcing a
> file or invoking a command). It is very helpful in backtracking through
> the code and even seeing the exact line of failure.
Sorry, but looking at the wiki entry describing hot errors, and playing
a bit with the feature, I still see static, text-oriented,
unsubstituted lines. For example:
... while executing
"f [expr rand()] [expr rand()]"
If you can bring back the exact rand() values that were passed to f at
the time the error occured, please please explain how !
-Alex
| |
| Robert Hicks 2006-06-26, 8:04 am |
| Could the final version be put somewhere like the wiki? It is ,
wouldn't want to lose it. : )
Robert
| |
|
|
Robert Hicks wrote:
> Could the final version be put somewhere like the wiki? It is ,
> wouldn't want to lose it. : )
Thanks.
I've just written the [traceback] page of thewiki:
http://wiki.tcl.tk/2626
Sorry for my lack of experience with wiki formatting...
Feel free to extend/rephrase/rewrite everything :-)
-Alex
|
|
|
|
|