diff --git a/js/src/jsnum.c b/js/src/jsnum.c index 676e55a185c..7c54c10b729 100644 --- a/js/src/jsnum.c +++ b/js/src/jsnum.c @@ -97,11 +97,8 @@ num_parseFloat(JSContext *cx, uintN argc, jsval *vp) str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - /* XXXbe js_strtod shouldn't require NUL termination */ - bp = js_UndependString(cx, str); - if (!bp) - return JS_FALSE; - if (!js_strtod(cx, bp, &ep, &d)) + bp = JSSTRING_CHARS(str); + if (!js_strtod(cx, bp, bp + JSSTRING_LENGTH(str), &ep, &d)) return JS_FALSE; if (ep == bp) { *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); @@ -133,11 +130,8 @@ num_parseInt(JSContext *cx, uintN argc, jsval *vp) str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - /* XXXbe js_strtointeger shouldn't require NUL termination */ - bp = js_UndependString(cx, str); - if (!bp) - return JS_FALSE; - if (!js_strtointeger(cx, bp, &ep, radix, &d)) + bp = JSSTRING_CHARS(str); + if (!js_strtointeger(cx, bp, bp + JSSTRING_LENGTH(str), &ep, radix, &d)) return JS_FALSE; if (ep == bp) { *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); @@ -706,7 +700,7 @@ js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) { JSObject *obj; JSString *str; - const jschar *bp, *ep; + const jschar *bp, *end, *ep; if (JSVAL_IS_OBJECT(v)) { obj = JSVAL_TO_OBJECT(v); @@ -723,20 +717,19 @@ js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) *dp = *JSVAL_TO_DOUBLE(v); } else if (JSVAL_IS_STRING(v)) { str = JSVAL_TO_STRING(v); + /* * Note that ECMA doesn't treat a string beginning with a '0' as an * octal number here. This works because all such numbers will be * interpreted as decimal by js_strtod and will never get passed to * js_strtointeger (which would interpret them as octal). */ - /* XXXbe js_strtod shouldn't require NUL termination */ - bp = js_UndependString(cx, str); - if (!bp) - return JS_FALSE; - if ((!js_strtod(cx, bp, &ep, dp) || - js_SkipWhiteSpace(ep) != bp + str->length) && - (!js_strtointeger(cx, bp, &ep, 0, dp) || - js_SkipWhiteSpace(ep) != bp + str->length)) { + bp = JSSTRING_CHARS(str); + end = bp + JSSTRING_LENGTH(str); + if ((!js_strtod(cx, bp, end, &ep, dp) || + js_SkipWhiteSpace(ep, end) != end) && + (!js_strtointeger(cx, bp, end, &ep, 0, dp) || + js_SkipWhiteSpace(ep, end) != end)) { goto badstr; } } else if (JSVAL_IS_BOOLEAN(v)) { @@ -877,15 +870,18 @@ js_DoubleToInteger(jsdouble d) JSBool -js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp) +js_strtod(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsdouble *dp) { + const jschar *s1; + size_t length, i; char cbuf[32]; - size_t i; char *cstr, *istr, *estr; JSBool negative; jsdouble d; - const jschar *s1 = js_SkipWhiteSpace(s); - size_t length = js_strlen(s1); + + s1 = js_SkipWhiteSpace(s, send); + length = send - s1; /* Use cbuf to avoid malloc */ if (length >= sizeof cbuf) { @@ -896,13 +892,12 @@ js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp) cstr = cbuf; } - for (i = 0; i <= length; i++) { - if (s1[i] >> 8) { - cstr[i] = 0; + for (i = 0; i != length; i++) { + if (s1[i] >> 8) break; - } cstr[i] = (char)s1[i]; } + cstr[i] = 0; istr = cstr; if ((negative = (*istr == '-')) != 0 || *istr == '+') @@ -979,41 +974,54 @@ static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr) } JSBool -js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, jsdouble *dp) +js_strtointeger(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsint base, jsdouble *dp) { + const jschar *s1, *start; JSBool negative; jsdouble value; - const jschar *start; - const jschar *s1 = js_SkipWhiteSpace(s); - if ((negative = (*s1 == '-')) != 0 || *s1 == '+') + s1 = js_SkipWhiteSpace(s, send); + if (s1 == send) + goto no_digits; + if ((negative = (*s1 == '-')) != 0 || *s1 == '+') { s1++; + if (s1 == send) + goto no_digits; + } if (base == 0) { /* No base supplied, or some base that evaluated to 0. */ if (*s1 == '0') { /* It's either hex or octal; only increment char if str isn't '0' */ - if (s1[1] == 'X' || s1[1] == 'x') { /* Hex */ - s1 += 2; + if (s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) { base = 16; - } else { /* Octal */ + s1 += 2; + if (s1 == send) + goto no_digits; + } else { base = 8; } } else { base = 10; /* Default to decimal. */ } - } else if (base == 16 && *s1 == '0' && (s1[1] == 'X' || s1[1] == 'x')) { + } else if (base == 16) { /* If base is 16, ignore hex prefix. */ - s1 += 2; + if (*s1 == '0' && s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) { + s1 += 2; + if (s1 == send) + goto no_digits; + } } /* * Done with the preliminaries; find some prefix of the string that's * a number in the given base. */ - start = s1; /* Mark - if string is empty, we return NaN. */ + JS_ASSERT(s1 < send); + start = s1; value = 0.0; - for (;;) { + do { uintN digit; jschar c = *s1; if ('0' <= c && c <= '9') @@ -1027,8 +1035,7 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, j if (digit >= (uintN)base) break; value = value * base + digit; - s1++; - } + } while (++s1 != send); if (value >= 9007199254740992.0) { if (base == 10) { @@ -1114,6 +1121,7 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint base, j /* We don't worry about inaccurate numbers for any other base. */ if (s1 == start) { + no_digits: *dp = 0.0; *ep = s; } else { diff --git a/js/src/jsnum.h b/js/src/jsnum.h index f2e4b16dddf..222cb3a3269 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -242,7 +242,8 @@ js_DoubleToInteger(jsdouble d); * Return false if out of memory. */ extern JSBool -js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp); +js_strtod(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsdouble *dp); /* * Similar to strtol except that it handles integers of arbitrary size. @@ -254,7 +255,8 @@ js_strtod(JSContext *cx, const jschar *s, const jschar **ep, jsdouble *dp); * Return false if out of memory. */ extern JSBool -js_strtointeger(JSContext *cx, const jschar *s, const jschar **ep, jsint radix, jsdouble *dp); +js_strtointeger(JSContext *cx, const jschar *s, const jschar *send, + const jschar **ep, jsint radix, jsdouble *dp); JS_END_EXTERN_C diff --git a/js/src/jsscan.c b/js/src/jsscan.c index e93a54551dc..85e38d88a69 100644 --- a/js/src/jsscan.c +++ b/js/src/jsscan.c @@ -1119,6 +1119,7 @@ js_GetToken(JSContext *cx, JSTokenStream *ts) /* The following 4 macros should only be used when TOKENBUF_OK() is true. */ #define TOKENBUF_BASE() (ts->tokenbuf.base) +#define TOKENBUF_END() (ts->tokenbuf.ptr) #define TOKENBUF_CHAR(i) (ts->tokenbuf.base[i]) #define TRIM_TOKENBUF(i) (ts->tokenbuf.ptr = ts->tokenbuf.base + i) #define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0) @@ -1443,14 +1444,16 @@ retry: if (!TOKENBUF_OK()) goto error; if (radix == 10) { - if (!js_strtod(cx, TOKENBUF_BASE(), &endptr, &dval)) { + if (!js_strtod(cx, TOKENBUF_BASE(), TOKENBUF_END(), + &endptr, &dval)) { js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); goto error; } } else { - if (!js_strtointeger(cx, TOKENBUF_BASE(), &endptr, radix, &dval)) { + if (!js_strtointeger(cx, TOKENBUF_BASE(), TOKENBUF_END(), + &endptr, radix, &dval)) { js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, JSMSG_OUT_OF_MEMORY); diff --git a/js/src/jsstr.c b/js/src/jsstr.c index 7251db71ef7..18e9843fadf 100644 --- a/js/src/jsstr.c +++ b/js/src/jsstr.c @@ -2861,10 +2861,10 @@ js_strchr_limit(const jschar *s, jschar c, const jschar *limit) } const jschar * -js_SkipWhiteSpace(const jschar *s) +js_SkipWhiteSpace(const jschar *s, const jschar *end) { - /* JS_ISSPACE is false on a null. */ - while (JS_ISSPACE(*s)) + JS_ASSERT(s <= end); + while (s != end && JS_ISSPACE(*s)) s++; return s; } diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 907c4c263dc..29f4ef80814 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -437,7 +437,7 @@ js_strchr_limit(const jschar *s, jschar c, const jschar *limit); * Return s advanced past any Unicode white space characters. */ extern const jschar * -js_SkipWhiteSpace(const jschar *s); +js_SkipWhiteSpace(const jschar *s, const jschar *end); /* * Inflate bytes to JS chars and vice versa. Report out of memory via cx