[wasm] Add argument checking to {WebAssembly.Function}.
This adds proper loading and parsing of the arguments that are being passed to the {WebAssembly.Function} constructor function, including tests covering most of the negative cases. R=jkummerow@chromium.org TEST=mjsunit/wasm/type-reflection BUG=v8:7742 Change-Id: Id4d67789604ee72aec5ad831004a01434c1c6d6f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1619748 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#61659}
This commit is contained in:
parent
2ca2f37073
commit
92ef97d57c
@ -1198,6 +1198,39 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
|
||||
}
|
||||
|
||||
// Determines the type encoded in a value type property (e.g. type reflection).
|
||||
// Returns false if there was an exception, true upon success. On success the
|
||||
// outgoing {type} is set accordingly, or set to {wasm::kWasmStmt} in case the
|
||||
// type could not be properly recognized.
|
||||
bool GetValueType(Isolate* isolate, MaybeLocal<Value> maybe,
|
||||
Local<Context> context, i::wasm::ValueType* type,
|
||||
i::wasm::WasmFeatures enabled_features) {
|
||||
v8::Local<v8::Value> value;
|
||||
if (!maybe.ToLocal(&value)) return false;
|
||||
v8::Local<v8::String> string;
|
||||
if (!value->ToString(context).ToLocal(&string)) return false;
|
||||
if (string->StringEquals(v8_str(isolate, "i32"))) {
|
||||
*type = i::wasm::kWasmI32;
|
||||
} else if (string->StringEquals(v8_str(isolate, "f32"))) {
|
||||
*type = i::wasm::kWasmF32;
|
||||
} else if (string->StringEquals(v8_str(isolate, "i64"))) {
|
||||
*type = i::wasm::kWasmI64;
|
||||
} else if (string->StringEquals(v8_str(isolate, "f64"))) {
|
||||
*type = i::wasm::kWasmF64;
|
||||
} else if (enabled_features.anyref &&
|
||||
string->StringEquals(v8_str(isolate, "anyref"))) {
|
||||
*type = i::wasm::kWasmAnyRef;
|
||||
} else if (enabled_features.anyref &&
|
||||
string->StringEquals(v8_str(isolate, "anyfunc"))) {
|
||||
*type = i::wasm::kWasmAnyFunc;
|
||||
} else {
|
||||
// Unrecognized type.
|
||||
*type = i::wasm::kWasmStmt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// WebAssembly.Global
|
||||
void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
@ -1213,6 +1246,7 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
}
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||
|
||||
// The descriptor's 'mutable'.
|
||||
bool is_mutable = false;
|
||||
@ -1232,27 +1266,8 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
{
|
||||
v8::MaybeLocal<v8::Value> maybe =
|
||||
descriptor->Get(context, v8_str(isolate, "value"));
|
||||
v8::Local<v8::Value> value;
|
||||
if (!maybe.ToLocal(&value)) return;
|
||||
v8::Local<v8::String> string;
|
||||
if (!value->ToString(context).ToLocal(&string)) return;
|
||||
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||
if (string->StringEquals(v8_str(isolate, "i32"))) {
|
||||
type = i::wasm::kWasmI32;
|
||||
} else if (string->StringEquals(v8_str(isolate, "f32"))) {
|
||||
type = i::wasm::kWasmF32;
|
||||
} else if (string->StringEquals(v8_str(isolate, "i64"))) {
|
||||
type = i::wasm::kWasmI64;
|
||||
} else if (string->StringEquals(v8_str(isolate, "f64"))) {
|
||||
type = i::wasm::kWasmF64;
|
||||
} else if (enabled_features.anyref &&
|
||||
string->StringEquals(v8_str(isolate, "anyref"))) {
|
||||
type = i::wasm::kWasmAnyRef;
|
||||
} else if (enabled_features.anyref &&
|
||||
string->StringEquals(v8_str(isolate, "anyfunc"))) {
|
||||
type = i::wasm::kWasmAnyFunc;
|
||||
} else {
|
||||
if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
|
||||
if (type == i::wasm::kWasmStmt) {
|
||||
thrower.TypeError(
|
||||
"Descriptor property 'value' must be 'i32', 'i64', 'f32', or "
|
||||
"'f64'");
|
||||
@ -1288,7 +1303,6 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
case i::wasm::kWasmI64: {
|
||||
int64_t i64_value = 0;
|
||||
if (!value->IsUndefined()) {
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||
if (!enabled_features.bigint) {
|
||||
thrower.TypeError("Can't set the value of i64 WebAssembly.Global");
|
||||
return;
|
||||
@ -1375,6 +1389,83 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
thrower.TypeError("WebAssembly.Function must be invoked with 'new'");
|
||||
return;
|
||||
}
|
||||
if (!args[0]->IsObject()) {
|
||||
thrower.TypeError("Argument 0 must be a function type");
|
||||
return;
|
||||
}
|
||||
Local<Object> function_type = Local<Object>::Cast(args[0]);
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
auto enabled_features = i::wasm::WasmFeaturesFromIsolate(i_isolate);
|
||||
|
||||
// Load the 'parameters' property of the function type.
|
||||
Local<String> parameters_key = v8_str(isolate, "parameters");
|
||||
v8::MaybeLocal<v8::Value> parameters_maybe =
|
||||
function_type->Get(context, parameters_key);
|
||||
v8::Local<v8::Value> parameters_value;
|
||||
if (!parameters_maybe.ToLocal(¶meters_value)) return;
|
||||
// TODO(7742): Allow any iterable, not just {Array} here.
|
||||
if (!parameters_value->IsArray()) {
|
||||
thrower.TypeError("Argument 0 must be a function type with 'parameters'");
|
||||
return;
|
||||
}
|
||||
Local<Array> parameters = parameters_value.As<Array>();
|
||||
uint32_t parameters_len = parameters->Length();
|
||||
if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
|
||||
thrower.TypeError("Argument 0 contains too many parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the 'results' property of the function type.
|
||||
Local<String> results_key = v8_str(isolate, "results");
|
||||
v8::MaybeLocal<v8::Value> results_maybe =
|
||||
function_type->Get(context, results_key);
|
||||
v8::Local<v8::Value> results_value;
|
||||
if (!results_maybe.ToLocal(&results_value)) return;
|
||||
// TODO(7742): Allow any iterable, not just {Array} here.
|
||||
if (!results_value->IsArray()) {
|
||||
thrower.TypeError("Argument 0 must be a function type with 'results'");
|
||||
return;
|
||||
}
|
||||
Local<Array> results = results_value.As<Array>();
|
||||
uint32_t results_len = results->Length();
|
||||
if (results_len > (enabled_features.mv
|
||||
? i::wasm::kV8MaxWasmFunctionMultiReturns
|
||||
: i::wasm::kV8MaxWasmFunctionReturns)) {
|
||||
thrower.TypeError("Argument 0 contains too many results");
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode the function type and construct a signature.
|
||||
i::Zone zone(i_isolate->allocator(), ZONE_NAME);
|
||||
i::wasm::FunctionSig::Builder builder(&zone, parameters_len, results_len);
|
||||
for (uint32_t i = 0; i < parameters_len; ++i) {
|
||||
i::wasm::ValueType type;
|
||||
MaybeLocal<Value> maybe = parameters->Get(context, i);
|
||||
if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
|
||||
if (type == i::wasm::kWasmStmt) {
|
||||
thrower.TypeError(
|
||||
"Argument 0 parameter type at index #%u must be a value type", i);
|
||||
return;
|
||||
}
|
||||
builder.AddParam(type);
|
||||
}
|
||||
for (uint32_t i = 0; i < results_len; ++i) {
|
||||
i::wasm::ValueType type;
|
||||
MaybeLocal<Value> maybe = results->Get(context, i);
|
||||
if (!GetValueType(isolate, maybe, context, &type, enabled_features)) return;
|
||||
if (type == i::wasm::kWasmStmt) {
|
||||
thrower.TypeError(
|
||||
"Argument 0 result type at index #%u must be a value type", i);
|
||||
return;
|
||||
}
|
||||
builder.AddReturn(type);
|
||||
}
|
||||
|
||||
if (!args[1]->IsFunction()) {
|
||||
thrower.TypeError("Argument 1 must be a function");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(7742): Implement ability to construct.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
@ -159,6 +159,7 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
})();
|
||||
|
||||
(function TestFunctionConstructor() {
|
||||
let toolong = new Array(1000 + 1);
|
||||
let desc = Object.getOwnPropertyDescriptor(WebAssembly, 'Function');
|
||||
assertEquals(typeof desc.value, 'function');
|
||||
assertTrue(desc.writable);
|
||||
@ -169,7 +170,33 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
assertEquals(WebAssembly.Function.name, 'Function');
|
||||
assertThrows(
|
||||
() => WebAssembly.Function(), TypeError, /must be invoked with 'new'/);
|
||||
// TODO(7742): Add tests for missing/bogus arguments.
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function(), TypeError,
|
||||
/Argument 0 must be a function type/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({}), TypeError,
|
||||
/Argument 0 must be a function type with 'parameters'/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[]}), TypeError,
|
||||
/Argument 0 must be a function type with 'results'/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:['foo'], results:[]}), TypeError,
|
||||
/Argument 0 parameter type at index #0 must be a value type/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[], results:['foo']}), TypeError,
|
||||
/Argument 0 result type at index #0 must be a value type/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:toolong, results:[]}), TypeError,
|
||||
/Argument 0 contains too many parameters/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[], results:toolong}), TypeError,
|
||||
/Argument 0 contains too many results/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[], results:[]}), TypeError,
|
||||
/Argument 1 must be a function/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[], results:[]}, {}), TypeError,
|
||||
/Argument 1 must be a function/);
|
||||
})();
|
||||
|
||||
(function TestFunctionExportedFunctions() {
|
||||
|
Loading…
Reference in New Issue
Block a user