Reviewed by Kevin.
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Aug 2004 21:44:42 +0000 (21:44 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Aug 2004 21:44:42 +0000 (21:44 +0000)
        - fix crashes in mozilla tests due to mishandling NaN

        * kjs/array_object.cpp: (ArrayProtoFuncImp::call): Rerranged range checks after
        calls to toInteger so that NaN will get turned into something that fits in an integer.
        These were the ones John already fixed, but his fix used isnan and the new fix is
        more efficient.

        * kjs/number_object.cpp: (NumberProtoFuncImp::call): Rearranged radix range checks
        after a call to toInteger to handle NaN properly. Also removed separate check
        for undefined that's not needed.

        * kjs/string_object.cpp: (StringProtoFuncImp::call): More of the same kinds of changes
        as in the above two files, but for a lot more functions. Also changed one place with
        an explicit check for undefined to instead just check isNaN.

        * tests/mozilla/run-mozilla-tests: Changed to invoke jst using $SYMROOTS for people
        like me who don't keep $SYMROOTS in their $PATH.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@7171 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/kjs/array_object.cpp
JavaScriptCore/kjs/number_object.cpp
JavaScriptCore/kjs/string_object.cpp
JavaScriptCore/tests/mozilla/run-mozilla-tests

index 37ca840c54ab511ac8971d681e14aac7e8804ef9..8f2c0a1d81460d621ad832e7d64b1d045aa6a3e2 100644 (file)
@@ -1,3 +1,25 @@
+2004-08-02  Darin Adler  <darin@apple.com>
+
+        Reviewed by Kevin.
+
+        - fix crashes in mozilla tests due to mishandling NaN
+
+        * kjs/array_object.cpp: (ArrayProtoFuncImp::call): Rerranged range checks after
+        calls to toInteger so that NaN will get turned into something that fits in an integer.
+        These were the ones John already fixed, but his fix used isnan and the new fix is
+        more efficient.
+
+        * kjs/number_object.cpp: (NumberProtoFuncImp::call): Rearranged radix range checks
+        after a call to toInteger to handle NaN properly. Also removed separate check
+        for undefined that's not needed.
+
+        * kjs/string_object.cpp: (StringProtoFuncImp::call): More of the same kinds of changes
+        as in the above two files, but for a lot more functions. Also changed one place with
+        an explicit check for undefined to instead just check isNaN.
+
+        * tests/mozilla/run-mozilla-tests: Changed to invoke jst using $SYMROOTS for people
+        like me who don't keep $SYMROOTS in their $PATH.
+
 === Safari-154 ===
 
 === Safari-153 ===
index 4219d3181fec135e7521d527054a6ee4d4b81dae..b7996242be37ed485ef7587e258d536da61d291e 100644 (file)
@@ -583,29 +583,24 @@ Value ArrayProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args
     double begin = 0;
     if (args[0].type() != UndefinedType) {
         begin = args[0].toInteger(exec);
-        if (isnan(begin)) {
-            begin = 0;
-        }
-        if (begin < 0) {
-            begin += length;
-            if (begin < 0)
-                begin = 0;
-        } else {
+        if (begin >= 0) { // false for NaN
             if (begin > length)
                 begin = length;
+        } else {
+            begin += length;
+            if (!(begin >= 0)) // true for NaN
+                begin = 0;
         }
     }
     double end = length;
     if (args[1].type() != UndefinedType) {
       end = args[1].toInteger(exec);
-      if (isnan(end)) {
-        end = length;
-      } else if (end < 0) {
+      if (end < 0) { // false for NaN
         end += length;
         if (end < 0)
           end = 0;
       } else {
-        if (end > length)
+        if (!(end <= length)) // true for NaN
           end = length;
       }
     }
index ba0854429f1b8fbef5051003962b204b1593c016..285c74b597ae9e5e987397de8a2f2f78459fb7fe 100644 (file)
@@ -88,16 +88,13 @@ Value NumberProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
     return err;
   }
 
-  // execute "toString()" or "valueOf()", respectively
   Value v = thisObj.internalValue();
   switch (id) {
   case ToString: {
     double dradix = 10;
-    if (!args.isEmpty() && args[0].type() != UndefinedType)
+    if (!args.isEmpty())
       dradix = args[0].toInteger(exec);
-    if (dradix < 2 || dradix > 36 || dradix == 10)
-      result = String(v.toString(exec));
-    else {
+    if (dradix >= 2 && dradix <= 36 && dradix != 10) { // false for NaN
       int radix = static_cast<int>(dradix);
       unsigned i = v.toUInt32(exec);
       char s[33];
@@ -108,7 +105,8 @@ Value NumberProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
         i /= radix;
       } while (i);
       result = String(p);
-    }
+    } else
+      result = String(v.toString(exec));
     break;
   }
   case ToLocaleString: /* TODO */
index 72bb72c7c8347cc7d06fe3b0a4176d6b91fc2da7..a4110a25485e3a5e2f9d8bba11be7d389b39b8b0 100644 (file)
@@ -204,20 +204,19 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
     break;
   case CharAt:
     dpos = a0.toInteger(exec);
-    if (dpos < 0 || dpos >= len)
-      u = "";
-    else
+    if (dpos >= 0 && dpos < len) // false for NaN
       u = s.substr(static_cast<int>(dpos), 1);
+    else
+      u = "";
     result = String(u);
     break;
   case CharCodeAt:
     dpos = a0.toInteger(exec);
-    if (dpos < 0 || dpos >= len)
-      d = NaN;
-    else {
+    if (dpos >= 0 && dpos < len) {// false for NaN
       UChar c = s[static_cast<int>(dpos)];
       d = (c.high() << 8) + c.low();
-    }
+    } else
+      d = NaN;
     result = Number(d);
     break;
   case Concat: {
@@ -234,10 +233,11 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
       dpos = 0;
     else {
       dpos = a1.toInteger(exec);
-      if (dpos < 0)
+      if (dpos >= 0) { // false for NaN
+        if (dpos > len)
+          dpos = len;
+      } else
         dpos = 0;
-      else if (dpos > len)
-        dpos = len;
     }
     d = s.find(u2, static_cast<int>(dpos));
     result = Number(d);
@@ -249,10 +249,11 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
       dpos = len;
     else {
       dpos = a1.toInteger(exec);
-      if (dpos < 0)
+      if (dpos >= 0) { // false for NaN
+        if (dpos > len)
+          dpos = len;
+      } else
         dpos = 0;
-      else if (dpos > len)
-        dpos = len;
     }
     d = s.rfind(u2, static_cast<int>(dpos));
     result = Number(d);
@@ -386,24 +387,24 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
     {
         // The arg processing is very much like ArrayProtoFunc::Slice
         double begin = args[0].toInteger(exec);
-        if (begin < 0) {
-          begin += len;
-          if (begin < 0)
-            begin = 0;
-        } else {
+        if (begin >= 0) { // false for NaN
           if (begin > len)
             begin = len;
+        } else {
+          begin += len;
+          if (!(begin >= 0)) // true for NaN
+            begin = 0;
         }
         double end = len;
         if (args[1].type() != UndefinedType) {
           end = args[1].toInteger(exec);
-          if (end < 0) {
-            end += len;
-            if (end < 0)
-              end = 0;
-          } else {
+          if (end >= 0) { // false for NaN
             if (end > len)
               end = len;
+          } else {
+            end += len;
+            if (!(end >= 0)) // true for NaN
+              end = 0;
           }
         }
         //printf( "Slicing from %d to %d \n", begin, end );
@@ -416,7 +417,7 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
     result = res;
     u = s;
     i = p0 = 0;
-    d = (a1.type() != UndefinedType) ? a1.toInteger(exec) : -1; // optional max number
+    d = a1.toInteger(exec);
     if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
       Object obj0 = Object::dynamicCast(a0);
       RegExp reg(obj0.get(exec,"source").toString(exec));
@@ -449,11 +450,11 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
          put(exec,lengthPropertyName, Number(0));
          break;
        } else {
-         while (i != d && i < u.size()-1)
+         while (!(i == d) && i < u.size()-1) // !(i == d) returns true for NaN
            res.put(exec, i++, String(u.substr(p0++, 1)));
        }
       } else {
-       while (i != d && (pos = u.find(u2, p0)) >= 0) {
+       while (!(i == d) && (pos = u.find(u2, p0)) >= 0) { // !(i == d) returns true for NaN
          res.put(exec, i, String(u.substr(p0, pos-p0)));
          p0 = pos + u2.size();
          i++;
@@ -461,7 +462,7 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
       }
     }
     // add remaining string, if any
-    if (i != d)
+    if (!(i == d)) // !(i == d) returns true for NaN
       res.put(exec, i++, String(u.substr(p0)));
     res.put(exec,lengthPropertyName, Number(i));
     }
@@ -469,12 +470,12 @@ Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &arg
   case Substr: {
     double d = a0.toInteger(exec);
     double d2 = a1.toInteger(exec);
-    if (d < 0) {
+    if (!(d >= 0)) { // true for NaN
       d += len;
-      if (d < 0)
+      if (!(d >= 0)) // true for NaN
         d = 0;
     }
-    if (a1.type() == UndefinedType)
+    if (isNaN(d2))
       d2 = len - d;
     else {
       if (d2 < 0)
index 4a25b727792de800a1ae164cfbebf146c43b88ec..dec586888aa072aacaa94a1eeea57f0dc3c99c1b 100755 (executable)
@@ -1,2 +1,2 @@
 perl jsDriver.pl -e kjs -L ecma/Date -f actual.html
-jst expected.html actual.html
+"$SYMROOTS/jst" expected.html actual.html