diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index b778c8d739..573b55cc85 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1768,6 +1768,35 @@ js::ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index) return true; } +// ES2017 draft 7.1.17 ToIndex +bool +js::ToIndex(JSContext* cx, JS::HandleValue v, uint64_t* index) +{ + // Step 1. + if (v.isUndefined()) { + *index = 0; + return true; + } + + // Step 2.a. + double integerIndex; + if (!ToInteger(cx, v, &integerIndex)) + return false; + + // Inlined version of ToLength. + // 1. Already an integer. + // 2. Step eliminates < 0, +0 == -0 with SameValueZero. + // 3/4. Limit to <= 2^53-1, so everything above should fail. + if (integerIndex < 0 || integerIndex >= DOUBLE_INTEGRAL_PRECISION_LIMIT) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX); + return false; + } + + // Step 3. + *index = uint64_t(integerIndex); + return true; +} + template bool js_strtod(ExclusiveContext* cx, const CharT* begin, const CharT* end, const CharT** dEnd, diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 9866a91eeb..bd53fdc1a0 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -308,6 +308,15 @@ MOZ_MUST_USE bool ToLengthClamped(T* cx, HandleValue v, uint32_t* out, bool* ove */ MOZ_MUST_USE bool ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index); +/* ES2017 draft 7.1.17 ToIndex + * + * Return true and set |*index| to the integer value if |v| is a valid + * integer index value. Otherwise report a RangeError and return false. + * + * The returned index will always be in the range 0 <= *index <= 2^53-1. + */ +MOZ_MUST_USE bool ToIndex(JSContext* cx, JS::HandleValue v, uint64_t* index); + MOZ_MUST_USE inline bool SafeAdd(int32_t one, int32_t two, int32_t* res) { diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 5d355ada9d..3bed40af47 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -264,27 +264,24 @@ ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp) return true; } -/* - * new ArrayBuffer(byteLength) - */ + +// ES2017 draft 24.1.2.1 bool ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); + // Step 1. if (!ThrowIfNotConstructing(cx, args, "ArrayBuffer")) return false; - int32_t nbytes = 0; - if (argc > 0 && !ToInt32(cx, args[0], &nbytes)) + // Step 2. + uint64_t byteLength; + if (!ToIndex(cx, args.get(0), &byteLength)) return false; - if (nbytes < 0) { - /* - * We're just not going to support arrays that are bigger than what will fit - * as an integer value; if someone actually ever complains (validly), then we - * can fix. - */ + // Non-standard: Refuse to allocate buffers larger than ~2 GiB. + if (byteLength > INT32_MAX) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); return false; } @@ -294,7 +291,7 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) return false; - JSObject* bufobj = create(cx, uint32_t(nbytes), proto); + JSObject* bufobj = create(cx, uint32_t(byteLength), proto); if (!bufobj) return false; args.rval().setObject(*bufobj); diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 0225c0578c..ac93ec9b14 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -1898,10 +1898,8 @@ DataViewObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) template /* static */ uint8_t* -DataViewObject::getDataPointer(JSContext* cx, Handle obj, double offset) +DataViewObject::getDataPointer(JSContext* cx, Handle obj, uint64_t offset) { - MOZ_ASSERT(offset >= 0); - const size_t TypeSize = sizeof(NativeType); if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, @@ -1989,31 +1987,6 @@ struct DataViewIO } }; -static bool -ToIndex(JSContext* cx, HandleValue v, double* index) -{ - if (v.isUndefined()) { - *index = 0.0; - return true; - } - - double integerIndex; - if (!ToInteger(cx, v, &integerIndex)) - return false; - - // Inlined version of ToLength. - // 1. Already an integer - // 2. Step eliminates < 0, +0 == -0 with SameValueZero - // 3/4. Limit to <= 2^53-1, so everything above should fail. - if (integerIndex < 0 || integerIndex > 9007199254740991) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX); - return false; - } - - *index = integerIndex; - return true; -} - template /* static */ bool DataViewObject::read(JSContext* cx, Handle obj, @@ -2023,7 +1996,7 @@ DataViewObject::read(JSContext* cx, Handle obj, // Step 3. unnecessary assert // Step 4. - double getIndex; + uint64_t getIndex; if (!ToIndex(cx, args.get(0), &getIndex)) return false; @@ -2111,7 +2084,7 @@ DataViewObject::write(JSContext* cx, Handle obj, // Step 3. unnecessary assert // Step 4. - double getIndex; + uint64_t getIndex; if (!ToIndex(cx, args.get(0), &getIndex)) return false; diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index ccdee22bee..196d347075 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -442,7 +442,7 @@ class DataViewObject : public NativeObject template static uint8_t* - getDataPointer(JSContext* cx, Handle obj, double offset); + getDataPointer(JSContext* cx, Handle obj, uint64_t offset); template static bool