mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 1284156 - Baldr: use ToNonWrappingUint32 for range checks (r=bbouvier)
MozReview-Commit-ID: 1oVQYPlF89J --HG-- extra : rebase_source : 365a915d22ee8bd72a3d7ed81fa3a910b96d2387
This commit is contained in:
parent
6a30ba8b4e
commit
171ec3369e
@ -330,7 +330,26 @@ js::InitWasmClass(JSContext* cx, HandleObject global)
|
||||
// Common functions
|
||||
|
||||
static bool
|
||||
GetResizableLimits(JSContext* cx, HandleObject obj, const char* kind, ResizableLimits* limits)
|
||||
ToNonWrappingUint32(JSContext* cx, HandleValue v, uint32_t max, const char* kind, const char* noun,
|
||||
uint32_t* u32)
|
||||
{
|
||||
double dbl;
|
||||
if (!ToInteger(cx, v, &dbl))
|
||||
return false;
|
||||
|
||||
if (dbl < 0 || dbl > max) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, kind, noun);
|
||||
return false;
|
||||
}
|
||||
|
||||
*u32 = uint32_t(dbl);
|
||||
MOZ_ASSERT(double(*u32) == dbl);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetResizableLimits(JSContext* cx, HandleObject obj, uint32_t max, const char* kind,
|
||||
ResizableLimits* limits)
|
||||
{
|
||||
JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
|
||||
if (!initialAtom)
|
||||
@ -341,17 +360,9 @@ GetResizableLimits(JSContext* cx, HandleObject obj, const char* kind, ResizableL
|
||||
if (!GetProperty(cx, obj, obj, initialId, &initialVal))
|
||||
return false;
|
||||
|
||||
double initialDbl;
|
||||
if (!ToInteger(cx, initialVal, &initialDbl))
|
||||
if (!ToNonWrappingUint32(cx, initialVal, max, kind, "initial size", &limits->initial))
|
||||
return false;
|
||||
|
||||
if (initialDbl < 0 || initialDbl > UINT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, kind, "initial");
|
||||
return false;
|
||||
}
|
||||
|
||||
limits->initial = uint32_t(initialDbl);
|
||||
|
||||
JSAtom* maximumAtom = Atomize(cx, "maximum", strlen("maximum"));
|
||||
if (!maximumAtom)
|
||||
return false;
|
||||
@ -363,16 +374,15 @@ GetResizableLimits(JSContext* cx, HandleObject obj, const char* kind, ResizableL
|
||||
if (!GetProperty(cx, obj, obj, maximumId, &maxVal))
|
||||
return false;
|
||||
|
||||
double maxDbl;
|
||||
if (!ToInteger(cx, maxVal, &maxDbl))
|
||||
limits->maximum.emplace();
|
||||
if (!ToNonWrappingUint32(cx, maxVal, max, kind, "maximum size", limits->maximum.ptr()))
|
||||
return false;
|
||||
|
||||
if (maxDbl < initialDbl || maxDbl > UINT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, kind, "maximum");
|
||||
if (limits->initial > *limits->maximum) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32,
|
||||
kind, "maximum size");
|
||||
return false;
|
||||
}
|
||||
|
||||
limits->maximum = Some(uint32_t(maxDbl));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -827,24 +837,12 @@ WasmMemoryObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
ResizableLimits limits;
|
||||
if (!GetResizableLimits(cx, obj, "Memory", &limits))
|
||||
if (!GetResizableLimits(cx, obj, UINT32_MAX / PageSize, "Memory", &limits))
|
||||
return false;
|
||||
|
||||
if (limits.initial > UINT32_MAX / PageSize) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Memory", "initial");
|
||||
return false;
|
||||
}
|
||||
|
||||
limits.initial *= PageSize;
|
||||
|
||||
if (limits.maximum) {
|
||||
if (limits.maximum.value() > UINT32_MAX / PageSize) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_SIZE, "Memory", "maximum");
|
||||
return false;
|
||||
}
|
||||
|
||||
limits.maximum = Some(limits.maximum.value() * PageSize);
|
||||
}
|
||||
if (limits.maximum)
|
||||
limits.maximum = Some(*limits.maximum * PageSize);
|
||||
|
||||
RootedArrayBufferObject buffer(cx,
|
||||
ArrayBufferObject::createForWasm(cx, limits.initial, limits.maximum));
|
||||
@ -891,16 +889,11 @@ WasmMemoryObject::growImpl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
RootedWasmMemoryObject memory(cx, &args.thisv().toObject().as<WasmMemoryObject>());
|
||||
|
||||
double deltaDbl;
|
||||
if (!ToInteger(cx, args.get(0), &deltaDbl))
|
||||
uint32_t delta;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), UINT32_MAX, "Memory", "grow delta", &delta))
|
||||
return false;
|
||||
|
||||
if (deltaDbl < 0 || deltaDbl > UINT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t ret = grow(memory, uint32_t(deltaDbl), cx);
|
||||
uint32_t ret = grow(memory, delta, cx);
|
||||
|
||||
if (ret == uint32_t(-1)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "memory");
|
||||
@ -1152,7 +1145,7 @@ WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
ResizableLimits limits;
|
||||
if (!GetResizableLimits(cx, obj, "Table", &limits))
|
||||
if (!GetResizableLimits(cx, obj, UINT32_MAX, "Table", &limits))
|
||||
return false;
|
||||
|
||||
RootedWasmTableObject table(cx, WasmTableObject::create(cx, limits));
|
||||
@ -1195,18 +1188,10 @@ WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
|
||||
RootedWasmTableObject tableObj(cx, &args.thisv().toObject().as<WasmTableObject>());
|
||||
const Table& table = tableObj->table();
|
||||
|
||||
double indexDbl;
|
||||
if (!ToInteger(cx, args.get(0), &indexDbl))
|
||||
uint32_t index;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "get index", &index))
|
||||
return false;
|
||||
|
||||
if (indexDbl < 0 || indexDbl >= table.length()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t index = uint32_t(indexDbl);
|
||||
MOZ_ASSERT(double(index) == indexDbl);
|
||||
|
||||
ExternalTableElem& elem = table.externalArray()[index];
|
||||
if (!elem.code) {
|
||||
args.rval().setNull();
|
||||
@ -1242,18 +1227,10 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
|
||||
if (!args.requireAtLeast(cx, "set", 2))
|
||||
return false;
|
||||
|
||||
double indexDbl;
|
||||
if (!ToInteger(cx, args[0], &indexDbl))
|
||||
uint32_t index;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "set index", &index))
|
||||
return false;
|
||||
|
||||
if (indexDbl < 0 || indexDbl >= table.length()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t index = uint32_t(indexDbl);
|
||||
MOZ_ASSERT(double(index) == indexDbl);
|
||||
|
||||
RootedFunction value(cx);
|
||||
if (!IsExportedFunction(args[1], &value) && !args[1].isNull()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_TABLE_VALUE);
|
||||
@ -1295,16 +1272,11 @@ WasmTableObject::growImpl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
RootedWasmTableObject table(cx, &args.thisv().toObject().as<WasmTableObject>());
|
||||
|
||||
double deltaDbl;
|
||||
if (!ToInteger(cx, args.get(0), &deltaDbl))
|
||||
uint32_t delta;
|
||||
if (!ToNonWrappingUint32(cx, args.get(0), UINT32_MAX, "Table", "grow delta", &delta))
|
||||
return false;
|
||||
|
||||
if (deltaDbl < 0 || deltaDbl > UINT32_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "table");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t ret = table->table().grow(uint32_t(deltaDbl), cx);
|
||||
uint32_t ret = table->table().grow(delta, cx);
|
||||
|
||||
if (ret == uint32_t(-1)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_GROW, "table");
|
||||
|
@ -22,7 +22,7 @@ const tab2Elem = new Table({initial:2, element:"anyfunc"});
|
||||
const tab3Elem = new Table({initial:3, element:"anyfunc"});
|
||||
const tab4Elem = new Table({initial:4, element:"anyfunc"});
|
||||
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum:1}), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum:1}), RangeError, /bad Memory maximum size/);
|
||||
|
||||
const m1 = new Module(textToBinary('(module (import "foo" "bar") (import "baz" "quux"))'));
|
||||
assertErrorMessage(() => new Instance(m1), TypeError, /no import object given/);
|
||||
@ -264,7 +264,7 @@ assertEq(e.tbl1.get(1), null);
|
||||
assertEq(e.tbl1.get(2), e.tbl1.get(2));
|
||||
assertEq(e.tbl1.get(2)(), 2);
|
||||
assertEq(e.tbl1.get(3), null);
|
||||
assertErrorMessage(() => e.tbl1.get(4), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => e.tbl1.get(4), RangeError, /bad Table get index/);
|
||||
assertEq(e.tbl1.get(1), null);
|
||||
e.tbl1.set(1, e.f3);
|
||||
assertEq(e.tbl1.get(1), e.f3);
|
||||
|
@ -117,11 +117,11 @@ assertEq(Memory.name, "Memory");
|
||||
assertErrorMessage(() => Memory(), TypeError, /constructor without new is forbidden/);
|
||||
assertErrorMessage(() => new Memory(1), TypeError, "first argument must be a memory descriptor");
|
||||
assertErrorMessage(() => new Memory({initial:{valueOf() { throw new Error("here")}}}), Error, "here");
|
||||
assertErrorMessage(() => new Memory({initial:-1}), TypeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:Math.pow(2,32)}), TypeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:1, maximum: Math.pow(2,32)/Math.pow(2,14) }), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum: 1 }), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({maximum: -1 }), TypeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:-1}), RangeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:Math.pow(2,32)}), RangeError, /bad Memory initial size/);
|
||||
assertErrorMessage(() => new Memory({initial:1, maximum: Math.pow(2,32)/Math.pow(2,14) }), RangeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({initial:2, maximum:1 }), RangeError, /bad Memory maximum size/);
|
||||
assertErrorMessage(() => new Memory({maximum: -1 }), RangeError, /bad Memory maximum size/);
|
||||
assertEq(new Memory({initial:1}) instanceof Memory, true);
|
||||
assertEq(new Memory({initial:1.5}).buffer.byteLength, WasmPage);
|
||||
|
||||
@ -169,8 +169,8 @@ const memGrow = memGrowDesc.value;
|
||||
assertEq(memGrow.length, 1);
|
||||
assertErrorMessage(() => memGrow.call(), TypeError, /called on incompatible undefined/);
|
||||
assertErrorMessage(() => memGrow.call({}), TypeError, /called on incompatible Object/);
|
||||
assertErrorMessage(() => memGrow.call(mem1, -1), Error, /failed to grow memory/);
|
||||
assertErrorMessage(() => memGrow.call(mem1, Math.pow(2,32)), Error, /failed to grow memory/);
|
||||
assertErrorMessage(() => memGrow.call(mem1, -1), RangeError, /bad Memory grow delta/);
|
||||
assertErrorMessage(() => memGrow.call(mem1, Math.pow(2,32)), RangeError, /bad Memory grow delta/);
|
||||
var mem = new Memory({initial:1, maximum:2});
|
||||
var buf = mem.buffer;
|
||||
assertEq(buf.byteLength, WasmPage);
|
||||
@ -205,10 +205,14 @@ assertErrorMessage(() => new Table({initial:1, element:1}), TypeError, /must be
|
||||
assertErrorMessage(() => new Table({initial:1, element:"any"}), TypeError, /must be "anyfunc"/);
|
||||
assertErrorMessage(() => new Table({initial:1, element:{valueOf() { return "anyfunc" }}}), TypeError, /must be "anyfunc"/);
|
||||
assertErrorMessage(() => new Table({initial:{valueOf() { throw new Error("here")}}, element:"anyfunc"}), Error, "here");
|
||||
assertErrorMessage(() => new Table({initial:-1, element:"anyfunc"}), TypeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), TypeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:-1, element:"anyfunc"}), RangeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:Math.pow(2,32), element:"anyfunc"}), RangeError, /bad Table initial size/);
|
||||
assertErrorMessage(() => new Table({initial:2, maximum:1, element:"anyfunc"}), RangeError, /bad Table maximum size/);
|
||||
assertErrorMessage(() => new Table({initial:2, maximum:Math.pow(2,32), element:"anyfunc"}), RangeError, /bad Table maximum size/);
|
||||
assertEq(new Table({initial:1, element:"anyfunc"}) instanceof Table, true);
|
||||
assertEq(new Table({initial:1.5, element:"anyfunc"}) instanceof Table, true);
|
||||
assertEq(new Table({initial:1, maximum:1.5, element:"anyfunc"}) instanceof Table, true);
|
||||
assertEq(new Table({initial:1, maximum:Math.pow(2,32)-1, element:"anyfunc"}) instanceof Table, true);
|
||||
|
||||
// 'WebAssembly.Table.prototype' data property
|
||||
const tableProtoDesc = Object.getOwnPropertyDescriptor(Table, 'prototype');
|
||||
@ -258,10 +262,10 @@ assertErrorMessage(() => get.call({}), TypeError, /called on incompatible Object
|
||||
assertEq(get.call(tbl1, 0), null);
|
||||
assertEq(get.call(tbl1, 1), null);
|
||||
assertEq(get.call(tbl1, 1.5), null);
|
||||
assertErrorMessage(() => get.call(tbl1, 2), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, 2.5), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, -1), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, Math.pow(2,33)), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => get.call(tbl1, 2), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, 2.5), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, -1), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, Math.pow(2,33)), RangeError, /bad Table get index/);
|
||||
assertErrorMessage(() => get.call(tbl1, {valueOf() { throw new Error("hi") }}), Error, "hi");
|
||||
|
||||
// 'WebAssembly.Table.prototype.set' data property
|
||||
@ -276,9 +280,9 @@ assertEq(set.length, 2);
|
||||
assertErrorMessage(() => set.call(), TypeError, /called on incompatible undefined/);
|
||||
assertErrorMessage(() => set.call({}), TypeError, /called on incompatible Object/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0), TypeError, /requires more than 1 argument/);
|
||||
assertErrorMessage(() => set.call(tbl1, 2, null), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => set.call(tbl1, -1, null), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), RangeError, /out-of-range index/);
|
||||
assertErrorMessage(() => set.call(tbl1, 2, null), RangeError, /bad Table set index/);
|
||||
assertErrorMessage(() => set.call(tbl1, -1, null), RangeError, /bad Table set index/);
|
||||
assertErrorMessage(() => set.call(tbl1, Math.pow(2,33), null), RangeError, /bad Table set index/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0, undefined), TypeError, /can only assign WebAssembly exported functions to Table/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0, {}), TypeError, /can only assign WebAssembly exported functions to Table/);
|
||||
assertErrorMessage(() => set.call(tbl1, 0, function() {}), TypeError, /can only assign WebAssembly exported functions to Table/);
|
||||
@ -298,8 +302,8 @@ const tblGrow = tblGrowDesc.value;
|
||||
assertEq(tblGrow.length, 1);
|
||||
assertErrorMessage(() => tblGrow.call(), TypeError, /called on incompatible undefined/);
|
||||
assertErrorMessage(() => tblGrow.call({}), TypeError, /called on incompatible Object/);
|
||||
assertErrorMessage(() => tblGrow.call(tbl1, -1), Error, /failed to grow table/);
|
||||
assertErrorMessage(() => tblGrow.call(tbl1, Math.pow(2,32)), Error, /failed to grow table/);
|
||||
assertErrorMessage(() => tblGrow.call(tbl1, -1), RangeError, /bad Table grow delta/);
|
||||
assertErrorMessage(() => tblGrow.call(tbl1, Math.pow(2,32)), RangeError, /bad Table grow delta/);
|
||||
var tbl = new Table({element:"anyfunc", initial:1, maximum:2});
|
||||
assertEq(tbl.length, 1);
|
||||
assertEq(tbl.grow(0), 1);
|
||||
|
@ -355,7 +355,7 @@ MSG_DEF(JSMSG_WASM_BAD_BUF_ARG, 0, JSEXN_TYPEERR, "first argument mus
|
||||
MSG_DEF(JSMSG_WASM_BAD_MOD_ARG, 0, JSEXN_TYPEERR, "first argument must be a WebAssembly.Module")
|
||||
MSG_DEF(JSMSG_WASM_BAD_DESC_ARG, 1, JSEXN_TYPEERR, "first argument must be a {0} descriptor")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMP_SIZE, 1, JSEXN_TYPEERR, "imported {0} with incompatible size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_SIZE, 2, JSEXN_TYPEERR, "bad {0} {1} size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_UINT32, 2, JSEXN_RANGEERR, "bad {0} {1}")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_TYPEERR, "imported {0} with incompatible maximum size")
|
||||
MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument, if present, must be an object")
|
||||
|
Loading…
Reference in New Issue
Block a user