mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
ported from UXP: Fix resizable DataView out-of-bounds semantics (aea80980)
This commit is contained in:
@@ -559,6 +559,7 @@ MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments")
|
||||
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0")
|
||||
MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer")
|
||||
MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer")
|
||||
MSG_DEF(JSMSG_DATA_VIEW_OUT_OF_BOUNDS, 0, JSEXN_TYPEERR, "attempting to access out-of-bounds DataView")
|
||||
MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%")
|
||||
MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object")
|
||||
MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}")
|
||||
|
||||
@@ -41,9 +41,9 @@ dv.setUint8(0, 44);
|
||||
assertEq(tracking[4], 44);
|
||||
|
||||
rab.resize(3);
|
||||
assertEq(dv.byteOffset, 0);
|
||||
assertEq(dv.byteLength, 0);
|
||||
assertThrowsInstanceOf(() => dv.getUint8(0), RangeError);
|
||||
assertThrowsInstanceOf(() => dv.byteOffset, TypeError);
|
||||
assertThrowsInstanceOf(() => dv.byteLength, TypeError);
|
||||
assertThrowsInstanceOf(() => dv.getUint8(0), TypeError);
|
||||
|
||||
rab.resize(6);
|
||||
assertEq(dv.byteOffset, 4);
|
||||
@@ -52,12 +52,40 @@ assertEq(dv.getUint8(0), 0);
|
||||
|
||||
var fixedDv = new DataView(rab, 4, 2);
|
||||
rab.resize(5);
|
||||
assertEq(fixedDv.byteOffset, 0);
|
||||
assertEq(fixedDv.byteLength, 0);
|
||||
assertThrowsInstanceOf(() => fixedDv.byteOffset, TypeError);
|
||||
assertThrowsInstanceOf(() => fixedDv.byteLength, TypeError);
|
||||
assertThrowsInstanceOf(() => fixedDv.getUint8(0), TypeError);
|
||||
rab.resize(6);
|
||||
assertEq(fixedDv.byteOffset, 4);
|
||||
assertEq(fixedDv.byteLength, 2);
|
||||
|
||||
var ctorRab = new ArrayBuffer(8, { maxByteLength: 8 });
|
||||
var ShrinkingNewTarget = new Proxy(function() {}, {
|
||||
get(target, prop, receiver) {
|
||||
if (prop === "prototype") {
|
||||
ctorRab.resize(2);
|
||||
return DataView.prototype;
|
||||
}
|
||||
return Reflect.get(target, prop, receiver);
|
||||
}
|
||||
});
|
||||
assertThrowsInstanceOf(() => Reflect.construct(DataView, [ctorRab, 4], ShrinkingNewTarget),
|
||||
RangeError);
|
||||
|
||||
var fixedCtorRab = new ArrayBuffer(8, { maxByteLength: 8 });
|
||||
var FixedShrinkingNewTarget = new Proxy(function() {}, {
|
||||
get(target, prop, receiver) {
|
||||
if (prop === "prototype") {
|
||||
fixedCtorRab.resize(5);
|
||||
return DataView.prototype;
|
||||
}
|
||||
return Reflect.get(target, prop, receiver);
|
||||
}
|
||||
});
|
||||
assertThrowsInstanceOf(() => Reflect.construct(DataView, [fixedCtorRab, 4, 2],
|
||||
FixedShrinkingNewTarget),
|
||||
RangeError);
|
||||
|
||||
var gsab = new SharedArrayBuffer(4, { maxByteLength: 16 });
|
||||
var sharedTracking = new Uint8Array(gsab);
|
||||
assertEq(sharedTracking.length, 4);
|
||||
|
||||
@@ -1885,7 +1885,18 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
|
||||
MOZ_ASSERT(byteOffset <= INT32_MAX);
|
||||
MOZ_ASSERT(byteLength <= INT32_MAX);
|
||||
MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
|
||||
|
||||
uint32_t bufferByteLength = arrayBuffer->byteLength();
|
||||
if (byteOffset > bufferByteLength ||
|
||||
(!lengthTracking && byteLength > bufferByteLength - byteOffset))
|
||||
{
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
||||
"1");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (lengthTracking)
|
||||
byteLength = bufferByteLength - byteOffset;
|
||||
|
||||
RootedObject proto(cx, protoArg);
|
||||
RootedObject obj(cx);
|
||||
@@ -1909,9 +1920,6 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
}
|
||||
}
|
||||
|
||||
// Caller should have established these preconditions, and no
|
||||
// (non-self-hosted) JS code has had an opportunity to run so nothing can
|
||||
// have invalidated them.
|
||||
MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
|
||||
MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
|
||||
|
||||
@@ -2171,6 +2179,11 @@ template <typename NativeType>
|
||||
DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint64_t offset,
|
||||
bool* isSharedMemory)
|
||||
{
|
||||
if (obj->isOutOfBounds()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS);
|
||||
return SharedMem<uint8_t*>::unshared(nullptr);
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -3208,7 +3221,13 @@ template<Value ValueGetter(DataViewObject* view)>
|
||||
bool
|
||||
DataViewObject::getterImpl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
args.rval().set(ValueGetter(&args.thisv().toObject().as<DataViewObject>()));
|
||||
Rooted<DataViewObject*> view(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
if (ValueGetter != bufferValue && view->isOutOfBounds()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS);
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().set(ValueGetter(view));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user