Closed Bug 444979 Opened 16 years ago Closed 16 years ago

switch statement considers -0 to be different from 0

Categories

(Core :: JavaScript Engine, defect)

x86
Windows XP
defect
Not set
normal

Tracking

()

VERIFIED FIXED

People

(Reporter: laszlo.janszky, Assigned: igor)

Details

(Keywords: testcase)

Attachments

(1 file, 4 obsolete files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.9) Gecko/2008052906 Firefox/3.0
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.9) Gecko/2008052906 Firefox/3.0

When you are trying to process with a switch statement -0, then case 0 doesn't works, so -0 is not equal to 0 in the switch.


Reproducible: Always

Steps to Reproduce:
<script>
var y=-0;
switch (y)
{
 case 0:
  alert("y=0")
  break;
 default:
  alert("y!=0")
}
</script>
Actual Results:  
alerts "y!=0"

Expected Results:  
alerts "y=0"
Version: unspecified → Trunk
Assignee: nobody → general
Component: General → JavaScript Engine
Product: Firefox → Core
QA Contact: general → general
Summary: javascript core switch negative zero bug → switch statement considers -0 to be different from 0
This is a bug in the implementation of optimized JSOP_TABLESWITCH/JSOP_LOOKUPSWITCH bytecodes. Adding for example, "case Math:" right before the default: label will give the "y==0"alert.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Assignee: general → igor
Flags: wanted1.9.0.x?
Keywords: regression
The bug is not a regression: the switch code simply has never accounted for the possibility of -O. Few initial revisions in CVS from 1998 of jsinterp.c do not have the bug, but that is because they effectively implemented == semantics, not ===, when comparing the switch value against the case labels. When the code was added on 1998-10-14 implementing the ECMA-specified === logic, it missed that -0 === 0.
Flags: wanted1.9.0.x?
Keywords: regression
Flags: wanted1.9.1?
Attached patch Fix (obsolete) — Splinter Review
The patch fixes the following test code (that is a modification of the original test case provided in the bug comments):

var shortSwitch = 'var y=-0;switch (y){case 0:  print("y=0");  break; default:  print("y!=0")}';
eval(shortSwitch);
print("Short switch completed");
var longSwitch = 'var y=-0;var t=0;switch(y){case -1:';
for (var i = 0; i < 64000; i++) {
	longSwitch += ' t++;';
}
longSwitch += ' break; case 0: print("y=0"); break; default: print("y!=0")}'
eval(longSwitch);
print("Long switch completed");

with the patch applied the output of the test code is
y=0
Short switch completed
y=0
Long switch completed
This effectively means the JS value -0 falls into the switch case 0.
Attachment #339960 - Flags: review?(igor)
Comment on attachment 339960 [details] [diff] [review]
Fix

>diff -r 15aecdaab936 js/src/jsinterp.cpp
>             rval = POP_OPND();
>-            if (!JSVAL_IS_INT(rval))
>-                DO_NEXT_OP(len);
>-            i = JSVAL_TO_INT(rval);
>+            if (!JSVAL_IS_INT(rval)&&!JSVAL_IS_DOUBLE(rval))
>+                DO_NEXT_OP(len);
>+            if (JSVAL_IS_INT(rval)) {
>+                i = JSVAL_TO_INT(rval);
>+            } else {
>+                if (*(JSVAL_TO_DOUBLE(rval)) == 0) {
>+                    i = 0;
>+                } else {
>+                    DO_NEXT_OP(len);
>+                }
>+            }

The code here uss JSVAL_IS_INT(rval) twice. Although a good compiler would be able to optimize that, it is important not to rely on that and ensure the optimal performance even for the price of extra source complexity. So the suggestion is to move checking JSVAL_IS_DOUBLE(rval) to the else part.
Attachment #339960 - Flags: review?(igor)
Attached patch Updated fix (obsolete) — Splinter Review
Updated according to Igor's comments
Attachment #339960 - Attachment is obsolete: true
Attachment #340142 - Flags: review?(igor)
Attached patch Updated fix (obsolete) — Splinter Review
Attachment #340142 - Attachment is obsolete: true
Attachment #340145 - Flags: review?(igor)
Attachment #340142 - Flags: review?(igor)
Attached patch Updated fix (obsolete) — Splinter Review
Attachment #340145 - Attachment is obsolete: true
Attachment #340148 - Flags: review?(igor)
Attachment #340145 - Flags: review?(igor)
Attachment #340148 - Flags: review?(igor) → review+
Comment on attachment 340148 [details] [diff] [review]
Updated fix

>+            } else if (JSVAL_IS_DOUBLE(rval) && *(JSVAL_TO_DOUBLE(rval)) == 0) {

Drive-by nit: don't overparenthesize operand of unary-*.

/be
Attached patch Updated fixSplinter Review
Attachment #340148 - Attachment is obsolete: true
Attachment #340321 - Flags: review?(igor)
Attachment #340321 - Flags: review?(igor) → review+
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
Keywords: testcase
/cvsroot/mozilla/js/tests/ecma_3/Statements/regress-444979.js,v  <--  regress-444979.js
initial revision: 1.1

http://hg.mozilla.org/mozilla-central/rev/f0e9fd501e63
Flags: in-testsuite+
Flags: in-litmus-
v 1.9.1
Status: RESOLVED → VERIFIED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: