mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Fix resizable DataView out-of-bounds semantics
This commit is contained in:
parent
93085352cd
commit
3751321a0e
3 changed files with 58 additions and 10 deletions
|
|
@ -555,6 +555,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);
|
||||
|
|
|
|||
|
|
@ -1886,7 +1886,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);
|
||||
|
|
@ -1910,9 +1921,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());
|
||||
|
||||
|
|
@ -2139,6 +2147,11 @@ template <typename NativeType>
|
|||
/* static */ uint8_t*
|
||||
DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint64_t offset)
|
||||
{
|
||||
if (obj->isOutOfBounds()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS);
|
||||
return 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,
|
||||
|
|
@ -3226,7 +3239,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue