Tcl Source Code

View Ticket
Login
Ticket UUID: 542588
Title: bug in expr error handler
Type: Bug Version: obsolete: 8.4a5
Submitter: nobody Created on: 2002-04-11 18:05:34
Subsystem: 47. Bytecode Compiler Assigned To: msofer
Priority: 5 Medium Severity:
Status: Closed Last Modified: 2002-04-18 21:01:20
Resolution: Fixed Closed By: msofer
    Closed on: 2002-04-18 14:01:20
Description:
% set begin 6658020034
6658020034
% set end   658020034
658020034
% expr abs($end - $begin)
integer value too large to represent
% expr { abs($end - $begin) }
can't use floating-point value as operand of "-"
% expr { abs(658020034 - 6658020034) }
integer value too large to represent
 
Can someone explain where Tcl thinks the floating
point value is?  And why is a floating point value
not a valid operand of "-"?

 - Phil Ehrens
 
This is just an example of too much sharing of a
common routine for producing an error message.

There's one routine for generating the "illegal
operand" error message, and by the time it is called,
the context isn't around any more to tailor the
message precisely. So the error message generator
knows that "658020034" was "bad", and it can see that
that is a legal floating-point value, so it assumes
that the error is that a floating-point value was used
where it should not be. Go ahead and file a bug report
under the "ByteCode Compiler" Category.

- Don Porter
User Comments: msofer added on 2002-04-18 21:01:20:

File Added - 21450: bug542588-tcl8.4.patch

Logged In: YES 
user_id=148712

Patch for tcl8.4 attached; committed to both HEAD and
core-8-3-1-branch.

The initial issue is solved; bug report #545661 was opened
for  the dependence of [expr]'s error handling on the timeof
compilation.

msofer added on 2002-04-18 19:43:46:

File Added - 21448: bug542588-tcl8.3.patch

Logged In: YES 
user_id=148712

Enclosing a patch for tcl8.3 sources that fixes the
immediate issue.

dkf added on 2002-04-18 15:28:57:
Logged In: YES 
user_id=79902

Problem is really that GET_WIDE_OR_INT (really just
Tcl_Get(Wide)IntFromObj) is failing due to integer range
overflow, and the code as it stands does not check for that
error case.  However, you can't always feed the value to
parse into Tcl_GetDoubleFromObj when GET_WIDE_OR_INT fails
due to things like invalid octal.  What's worse, the nature
of the failure has vanished at this point because
GET_WIDE_OR_INT does not use an interpreter, and
Tcl_Get(Wide)IntFromObj resets errno...  :^(

msofer added on 2002-04-18 04:12:31:
Logged In: YES 
user_id=148712

No, it never gets to 'abs'; note that it is '-' complaining
about a non valid operand. Doubles are acceptable operands
for 'abs'.

Look at what is happening in INST_SUB: TclLooksLikeInt
returns 1, so GetIntFromObj is called and it fails, so that
IllegalExprOperandType gets called. GetDoubleFromObj is
never called (it is called only when TclLooksLikeInt fails). 

The problem is indeed that IllegalExprOperandType is not
expecting to receive "too large integers". The local fix
there will produce something like

% expr { abs($end - $begin) }
can't use integer value too large to represent as operand of
"-" 

The case

% expr abs($end - $begin)
integer value too large to represent 

is caught earlier, before subtraction is ever attempted.

hobbs added on 2002-04-18 03:13:48:
Logged In: YES 
user_id=72656

I believe the reason that the compiled object version fails 
with a different message is that it will first try and get 
it with GetIntFromObj, which fails.  It then tries 
GetDoubleFromObj, which succeeds (because strtod has larger 
range acceptance), but then fails as doubles (floats) 
aren't accepted for abs.

In the static case, it fails because it succeeds the 
LooksLikeInt, which means it is either an acceptable int or 
one too large to represent.

Quite simple, no?

In the first case, it's Tcl that sub's end and begin, not 
the expr parser, so you get the too large int again.

msofer added on 2002-04-18 02:57:31:
Logged In: YES 
user_id=148712

Indeed; the cause of the bug is that the error handler for
operations in the bc engine (IllegalExprOperandType) assumes
that it can only get empty strings, bad octals or (default)
floating point values. So, a superficial fix just touches that.

The issue that is worrying me is: is this really a "bad
operand" issue, or should the error have been caught
earlier? As there are two different execution paths for
[expr] (braced vs unbraced), and they seem to behave
differently ...

Anyway, I'll fix the immediate issue and log a new bug
report with the deeper one. Sorry for messing up the discussion.

nobody added on 2002-04-18 02:46:51:
Logged In: NO 

Boy, if I went so far off-topic in one of my bug reports
here I would be flayed alive.

The problem, whatever caused it, is that the error message
reported per my original bug report is wrong by anybody's
measure of wrongness... except possibly Ariel Sharon,
whose measure seems to have a directional component which
makes it unreliable.

hobbs added on 2002-04-18 02:40:48:
Logged In: YES 
user_id=72656

I don't think you are reading the docs right (or they 
aren't written clearly).  'expr foo' fails as well, but 
expr {"foo"} and expr {"08"} are both OK.

msofer added on 2002-04-17 19:58:53:
Logged In: YES 
user_id=148712

According to expr.n:
"If no numeric interpretation is possible, then an operand
is left as a string (and only a limited set  of operators
may be applied to it)."

As I understand that, the following is indeed a bug:

% set a 08
08
% expr $a
"08" is an invalid octal number
% expr 08
"08" is an invalid octal number

The source of misunderstanding is obviously in "no numeric
representation is possible": tcl seems to say that "08" can
 be represented as a number, which happens to be invalid -
I'd rather say that 08 cannot be represented as a number. 

In the same vein, how should we interpret a string of digits
that is too large to represent as an integer: "an integer
too large to represent", or "a string that cannot be
represented as a number"?

hobbs added on 2002-04-17 06:03:28:
Logged In: YES 
user_id=72656

No, those are being treated as normal strings.  That has 
always been a behavior of expr.

msofer added on 2002-04-17 06:00:39:
Logged In: YES 
user_id=148712

Are these bugs too?

% set a 08
08
% expr $a
"08" is an invalid octal number
% expr {$a}
08
% set b 665802003400000000000000
665802003400000000000000
% expr $b
integer value too large to represent
% expr {$b}
665802003400000000000000

andreas_kupries added on 2002-04-17 05:58:50:
Logged In: YES 
user_id=75003

Ok. I also prefer that the path should produce the same 
message. If that is not possible I am willing to settle for 
different yet correct messages.

msofer added on 2002-04-17 05:55:20:
Logged In: YES 
user_id=148712

Yes, in my mind (and in the evolving patch), the problem to
fix is "both paths should produce the same error messages,
but don't". All of these fall in *that* category, although
some are less severe as they produce different but correct
messages. Maybe it is not necessary to produce the same
error message,as long as it is a correct one?

andreas_kupries added on 2002-04-17 05:47:21:
Logged In: YES 
user_id=75003

Why is that a sibling ?

The leading 0 tells tcl to interpret 08 as an octal number, 
but 8 is not a valid octal digit, Hence it is an invalid 
octal number, and the message is essentially correct in 
both cases. Or is the problem that the message is different 
for the two cases ?

msofer added on 2002-04-17 05:46:01:
Logged In: YES 
user_id=148712

More ...

% set a 08
08
% expr abs($a)
"08" is an invalid octal number
% expr {abs($a)}
argument to math function was an invalid octal number

The error cases follow a different path, and produce
different results.In this particular case, I like the second
one better ...

msofer added on 2002-04-17 05:41:27:
Logged In: YES 
user_id=148712

Another sibling is

% set a 08
08
% expr $a+1
"08" is an invalid octal number
% expr {$a+1}
can't use invalid octal number as operand of "+"

msofer added on 2002-04-16 22:45:01:
Logged In: YES 
user_id=148712

Related bug (the relationship is in the cause, not the symptom):

% set begin 665802003400000000000000
665802003400000000000000
% expr {1 && $begin}
1
% expr 1 && $begin
integer value too large to represent

msofer added on 2002-04-16 01:40:47:
Logged In: YES 
user_id=148712

Note that 'abs' has nothing to do with it

% set begin 665802003400000000000000
665802003400000000000000
% expr $begin - 1
integer value too large to represent
% expr {$begin - 1}
can't use floating-point value as operand of "-"

msofer added on 2002-04-16 01:34:16:
Logged In: YES 
user_id=148712

Note that this particular example fails to produce the error
in tcl8.5 (Donal's 64 bit arithmetic), but it can be
reproduced by going beyong the 64-bit limit:
   set begin 665802003400000000000000

Attachments: