Commit 0679765d authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[asm.js] Test and fix return type validation.

This fixes cases where falling off the end of a non-void function was
accepted as a valid asm.js module. This led to translation failures in
the WASM code. Only void functions are allowed to fall off the end.

R=clemensh@chromium.org
TEST=mjsunit/asm/return-types
BUG=chromium:719286

Change-Id: I7b1c9ba5381b87a23cf0a2171bee5e5f5e8cd9de
Reviewed-on: https://chromium-review.googlesource.com/500312
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45221}
parent a1f00971
......@@ -613,7 +613,7 @@ void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) {
void AsmJsParser::ValidateExport() {
// clang-format off
EXPECT_TOKEN(TOK(return));
// clang format on
// clang-format on
if (Check('{')) {
for (;;) {
Vector<const char> name = CopyCurrentIdentifierString();
......@@ -744,14 +744,23 @@ void AsmJsParser::ValidateFunction() {
function_temp_locals_used_ = 0;
function_temp_locals_depth_ = 0;
bool last_statement_is_return = false;
while (!failed_ && !Peek('}')) {
// clang-format off
last_statement_is_return = Peek(TOK(return));
// clang-format on
RECURSE(ValidateStatement());
}
EXPECT_TOKEN('}');
if (return_type_ == nullptr) {
return_type_ = AsmType::Void();
if (!last_statement_is_return) {
if (return_type_ == nullptr) {
return_type_ = AsmType::Void();
} else if (!return_type_->IsA(AsmType::Void())) {
FAIL("Expected return at end of non-void function");
}
}
DCHECK_NOT_NULL(return_type_);
// TODO(bradnelson): WasmModuleBuilder can't take this in the right order.
// We should fix that so we can use it instead.
......@@ -1066,7 +1075,7 @@ void AsmJsParser::IfStatement() {
// 6.5.5 ReturnStatement
void AsmJsParser::ReturnStatement() {
// clang-format off
EXPECT_TOKEN(TOK(return ));
EXPECT_TOKEN(TOK(return));
// clang-format on
if (!Peek(';') && !Peek('}')) {
// TODO(bradnelson): See if this can be factored out.
......@@ -1081,8 +1090,10 @@ void AsmJsParser::ReturnStatement() {
} else {
FAIL("Invalid return type");
}
} else {
} else if (return_type_ == nullptr) {
return_type_ = AsmType::Void();
} else if (!return_type_->IsA(AsmType::Void())) {
FAIL("Invalid void return type");
}
current_function_builder_->Emit(kExprReturn);
SkipSemicolon();
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --validate-asm
(function SuccessReturnTypesMatch() {
function Module(stdlib, imports, heap) {
"use asm";
function f(a) {
a = a | 0;
if ((a | 0) == 1) return 2.3;
if ((a | 0) == 2) return 4.2;
return 6.5;
}
return { f:f };
}
var m = Module(this);
assertTrue(%IsAsmWasmCode(Module));
assertEquals(2.3, m.f(1));
assertEquals(4.2, m.f(2));
assertEquals(6.5, m.f(3));
})();
(function FailReturnTypesMismatch() {
function Module(stdlib, imports, heap) {
"use asm";
function f(a) {
a = a | 0;
if ((a | 0) == 1) return 2.3;
if ((a | 0) == 2) return 123;
return 4.2;
}
return { f:f };
}
var m = Module(this);
assertFalse(%IsAsmWasmCode(Module));
assertEquals(2.3, m.f(1));
assertEquals(123, m.f(2));
assertEquals(4.2, m.f(3));
})();
(function FailFallOffNonVoidFunction() {
function Module(stdlib, imports, heap) {
"use asm";
function f(a) {
a = a | 0;
if ((a | 0) == 1) return 2.3;
if ((a | 0) == 2) return 4.2;
}
return { f:f };
}
var m = Module(this);
assertFalse(%IsAsmWasmCode(Module));
assertEquals(2.3, m.f(1));
assertEquals(4.2, m.f(2));
assertEquals(undefined, m.f(3));
})();
(function FailNonVoidVoidMismatch() {
function Module(stdlib, imports, heap) {
"use asm";
function f(a) {
a = a | 0;
if ((a | 0) == 1) return 2.3;
if ((a | 0) == 2) return;
}
return { f:f };
}
var m = Module(this);
assertFalse(%IsAsmWasmCode(Module));
assertEquals(2.3, m.f(1));
assertEquals(undefined, m.f(2));
assertEquals(undefined, m.f(3));
})();
(function FailVoidNonVoidMismatch() {
function Module(stdlib, imports, heap) {
"use asm";
function f(a) {
a = a | 0;
if ((a | 0) == 1) return;
if ((a | 0) == 2) return 2.3;
}
return { f:f };
}
var m = Module(this);
assertFalse(%IsAsmWasmCode(Module));
assertEquals(undefined, m.f(1));
assertEquals(2.3, m.f(2));
assertEquals(undefined, m.f(3));
})();
(function SuccessVoidFunction() {
function Module(stdlib, imports, heap) {
"use asm";
function f(a) {
a = a | 0;
if ((a | 0) == 1) return;
return;
}
return { f:f };
}
var m = Module(this);
assertTrue(%IsAsmWasmCode(Module));
assertEquals(undefined, m.f(1));
assertEquals(undefined, m.f(2));
})();
(function SuccessFallOffVoidFunction() {
function Module(stdlib, imports, heap) {
"use asm";
function f(a) {
a = a | 0;
if ((a | 0) == 1) return;
}
return { f:f };
}
var m = Module(this);
assertTrue(%IsAsmWasmCode(Module));
assertEquals(undefined, m.f(1));
assertEquals(undefined, m.f(2));
})();
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