Commit 39eab44d authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Check signature for {WasmJSFunction} imports.

This add signature checking when a constructed {WebAssembly.Function} is
being imported into a module. Signatures must match exactly. Note that
importing itself is not yet implemented and will be done as a follow-up.

R=ahaas@chromium.org
TEST=mjsunit/wasm/type-reflection
BUG=v8:7742

Change-Id: Iaa3fee574f8edafdddfc9e7aafe2bbd1ae597ff2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1683729
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62502}
parent f690334b
......@@ -5963,9 +5963,9 @@ WasmImportCallKind GetWasmImportCallKind(Handle<JSReceiver> target,
wasm::FunctionSig* expected_sig,
bool has_bigint_feature) {
if (WasmExportedFunction::IsWasmExportedFunction(*target)) {
auto imported_function = WasmExportedFunction::cast(*target);
auto func_index = imported_function.function_index();
auto module = imported_function.instance().module();
auto imported_function = Handle<WasmExportedFunction>::cast(target);
auto func_index = imported_function->function_index();
auto module = imported_function->instance().module();
wasm::FunctionSig* imported_sig = module->functions[func_index].sig;
if (*imported_sig != *expected_sig) {
return WasmImportCallKind::kLinkError;
......@@ -5977,9 +5977,17 @@ WasmImportCallKind GetWasmImportCallKind(Handle<JSReceiver> target,
}
return WasmImportCallKind::kWasmToWasm;
}
if (WasmJSFunction::IsWasmJSFunction(*target)) {
auto js_function = Handle<WasmJSFunction>::cast(target);
if (!js_function->MatchesSignature(expected_sig)) {
return WasmImportCallKind::kLinkError;
}
// TODO(7742): Implement proper handling of this case.
UNIMPLEMENTED();
}
if (WasmCapiFunction::IsWasmCapiFunction(*target)) {
WasmCapiFunction capi_function = WasmCapiFunction::cast(*target);
if (!capi_function.IsSignatureEqual(expected_sig)) {
auto capi_function = Handle<WasmCapiFunction>::cast(target);
if (!capi_function->IsSignatureEqual(expected_sig)) {
return WasmImportCallKind::kLinkError;
}
return WasmImportCallKind::kWasmToCapi;
......
......@@ -558,6 +558,11 @@ class PodArray : public ByteArray {
length * sizeof(T));
}
bool matches(const T* buffer, int length) {
DCHECK_LE(length, this->length());
return memcmp(GetDataStartAddress(), buffer, length * sizeof(T)) == 0;
}
T get(int index) {
T result;
copy_out(index, &result, 1);
......
......@@ -2310,6 +2310,21 @@ wasm::FunctionSig* WasmJSFunction::GetSignature(Zone* zone) {
return new (zone) wasm::FunctionSig(return_count, parameter_count, types);
}
bool WasmJSFunction::MatchesSignature(wasm::FunctionSig* sig) {
DCHECK_LE(sig->all().size(), kMaxInt);
int sig_size = static_cast<int>(sig->all().size());
int return_count = static_cast<int>(sig->return_count());
int parameter_count = static_cast<int>(sig->parameter_count());
WasmJSFunctionData function_data = shared().wasm_js_function_data();
if (return_count != function_data.serialized_return_count() ||
parameter_count != function_data.serialized_parameter_count()) {
return false;
}
if (sig_size == 0) return true; // Prevent undefined behavior.
const wasm::ValueType* expected = sig->all().begin();
return function_data.serialized_signature().matches(expected, sig_size);
}
Address WasmCapiFunction::GetHostCallTarget() const {
return shared().wasm_capi_function_data().call_target();
}
......
......@@ -700,6 +700,7 @@ class WasmJSFunction : public JSFunction {
// Deserializes the signature of this function using the provided zone. Note
// that lifetime of the signature is hence directly coupled to the zone.
wasm::FunctionSig* GetSignature(Zone* zone);
bool MatchesSignature(wasm::FunctionSig* sig);
DECL_CAST(WasmJSFunction)
OBJECT_CONSTRUCTORS(WasmJSFunction, JSFunction);
......
......@@ -293,3 +293,39 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
table.set(1, fun3);
assertTraps(kTrapFuncSigMismatch, () => instance.exports.main(1));
})();
// TODO(7742): Enable once imported constructed functions are callable.
/*(function TestFunctionModuleImportMatchingSig() {
let builder = new WasmModuleBuilder();
let fun = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
let fun_index = builder.addImport("m", "fun", kSig_i_v)
builder.addFunction('main', kSig_i_v)
.addBody([
kExprCallFunction, fun_index
])
.exportFunc();
let instance = builder.instantiate({ m: { fun: fun }});
assertEquals(7, instance.exports.main());
})();*/
(function TestFunctionModuleImportMatchingSig() {
let builder = new WasmModuleBuilder();
let fun1 = new WebAssembly.Function({parameters:[], results:[]}, _ => 7);
let fun2 = new WebAssembly.Function({parameters:["i32"], results:[]}, _ => 8);
let fun3 = new WebAssembly.Function({parameters:[], results:["f32"]}, _ => 9);
let fun_index = builder.addImport("m", "fun", kSig_i_v)
builder.addFunction('main', kSig_i_v)
.addBody([
kExprCallFunction, fun_index
])
.exportFunc();
assertThrows(
() => builder.instantiate({ m: { fun: fun1 }}), WebAssembly.LinkError,
/imported function does not match the expected type/);
assertThrows(
() => builder.instantiate({ m: { fun: fun2 }}), WebAssembly.LinkError,
/imported function does not match the expected type/);
assertThrows(
() => builder.instantiate({ m: { fun: fun3 }}), WebAssembly.LinkError,
/imported function does not match the expected type/);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment