+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 ===
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];
i /= radix;
} while (i);
result = String(p);
- }
+ } else
+ result = String(v.toString(exec));
break;
}
case ToLocaleString: /* TODO */
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: {
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);
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);
{
// 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 );
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));
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++;
}
}
// 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));
}
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)