[wasm] [interpreter] Handle ToNumber failure on imports

We were already handling the case that a called import throws, but if
it returned an error which is not convertible to a number, we failed
with a CHECK error.
This CL fixes this.

R=titzer@chromium.org

Bug: chromium:771970
Change-Id: I6c9983459109d49c43304610b696d49de986a250
Reviewed-on: https://chromium-review.googlesource.com/735354
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Ben Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48912}
This commit is contained in:
Clemens Hammacher 2017-10-25 11:29:26 +02:00 committed by Commit Bot
parent 5867270651
commit 68a087f811
2 changed files with 33 additions and 5 deletions

View File

@ -1076,12 +1076,14 @@ Handle<Object> WasmValueToNumber(Factory* factory, WasmValue val,
// Convert JS value to WebAssembly, spec here:
// https://github.com/WebAssembly/design/blob/master/JS.md#towebassemblyvalue
// Return WasmValue() (i.e. of type kWasmStmt) on failure. In that case, an
// exception will be pending on the isolate.
WasmValue ToWebAssemblyValue(Isolate* isolate, Handle<Object> value,
wasm::ValueType type) {
switch (type) {
case kWasmI32: {
MaybeHandle<Object> maybe_i32 = Object::ToInt32(isolate, value);
// TODO(clemensh): Handle failure here (unwind).
if (maybe_i32.is_null()) return {};
int32_t value;
CHECK(maybe_i32.ToHandleChecked()->ToInt32(&value));
return WasmValue(value);
@ -1091,13 +1093,13 @@ WasmValue ToWebAssemblyValue(Isolate* isolate, Handle<Object> value,
UNREACHABLE();
case kWasmF32: {
MaybeHandle<Object> maybe_number = Object::ToNumber(value);
// TODO(clemensh): Handle failure here (unwind).
if (maybe_number.is_null()) return {};
return WasmValue(
static_cast<float>(maybe_number.ToHandleChecked()->Number()));
}
case kWasmF64: {
MaybeHandle<Object> maybe_number = Object::ToNumber(value);
// TODO(clemensh): Handle failure here (unwind).
if (maybe_number.is_null()) return {};
return WasmValue(maybe_number.ToHandleChecked()->Number());
}
default:
@ -1264,7 +1266,7 @@ class ThreadImpl {
WasmInterpreter::Thread::ExceptionHandlingResult HandleException(
Isolate* isolate) {
DCHECK(isolate->has_pending_exception());
// TODO(wasm): Add wasm exception handling (would return true).
// TODO(wasm): Add wasm exception handling (would return HANDLED).
USE(isolate->pending_exception());
TRACE("----- UNWIND -----\n");
DCHECK_LT(0, activations_.size());
@ -2209,7 +2211,10 @@ class ThreadImpl {
if (signature->return_count() > 0) {
// TODO(wasm): Handle multiple returns.
DCHECK_EQ(1, signature->return_count());
Push(ToWebAssemblyValue(isolate, retval, signature->GetReturn()));
WasmValue value =
ToWebAssemblyValue(isolate, retval, signature->GetReturn());
if (value.type() == kWasmStmt) return TryHandleException(isolate);
Push(value);
}
return {ExternalCallResult::EXTERNAL_RETURNED};
}

View File

@ -398,3 +398,26 @@ function checkStack(stack, expected_lines) {
run(x => (x - 18));
}
})();
(function testImportThrowsOnToNumber() {
const builder = new WasmModuleBuilder();
builder.addImport('mod', 'func', kSig_i_v);
builder.addFunction('main', kSig_i_v)
.addBody([kExprCallFunction, 0])
.exportFunc();
var num_callback_calls = 0;
const callback = () => {
++num_callback_calls;
return Symbol()
};
var instance = builder.instantiate({mod: {func: callback}});
// Test that this does not mess up internal state by executing it three times.
for (var i = 0; i < 3; ++i) {
var interpreted_before = %WasmNumInterpretedCalls(instance);
assertThrows(
() => instance.exports.main(), TypeError,
'Cannot convert a Symbol value to a number');
assertEquals(interpreted_before + 1, %WasmNumInterpretedCalls(instance));
assertEquals(i + 1, num_callback_calls);
}
})();