Commit a621462b authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[asm.js] Fix excessive function table sizes.

This fixes crashes during validation when trying to construct modules
with excessively large function tables. The {WasmModuleBuilder} now
gracefully checks against existing WebAssembly implementation limits.

R=clemensh@chromium.org
TEST=mjsunit/regress/regress-crbug-715455
BUG=chromium:715455

Change-Id: Ia9738cb0b49a1eb4caf073b75301c0303f295699
Reviewed-on: https://chromium-review.googlesource.com/509530
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45429}
parent 098bd2a3
......@@ -195,16 +195,6 @@ class AsmJsParser::TemporaryVariableScope {
int local_depth_;
};
AsmJsParser::VarInfo::VarInfo()
: type(AsmType::None()),
function_builder(nullptr),
import(nullptr),
mask(-1),
index(0),
kind(VarKind::kUnused),
mutable_variable(true),
function_defined(false) {}
wasm::AsmJsParser::VarInfo* AsmJsParser::GetVarInfo(
AsmJsScanner::token_t token) {
if (AsmJsScanner::IsGlobal(token)) {
......@@ -680,7 +670,6 @@ void AsmJsParser::ValidateFunctionTable() {
// Only store the function into a table if we used the table somewhere
// (i.e. tables are first seen at their use sites and allocated there).
if (table_info->kind == VarKind::kTable) {
DCHECK_GE(table_info->mask, 0);
if (count >= static_cast<uint64_t>(table_info->mask) + 1) {
FAIL("Exceeded function table size");
}
......@@ -2034,29 +2023,27 @@ AsmType* AsmJsParser::ValidateCall() {
if (!CheckForUnsigned(&mask)) {
FAILn("Expected mask literal");
}
// TODO(mstarzinger): Clarify and explain where this limit is coming from,
// as it is not mandated by the spec directly.
if (mask > 0x7fffffff) {
FAILn("Expected power of 2 mask");
}
if (!base::bits::IsPowerOfTwo32(static_cast<uint32_t>(1 + mask))) {
if (!base::bits::IsPowerOfTwo32(mask + 1)) {
FAILn("Expected power of 2 mask");
}
current_function_builder_->EmitI32Const(static_cast<uint32_t>(mask));
current_function_builder_->EmitI32Const(mask);
current_function_builder_->Emit(kExprI32And);
EXPECT_TOKENn(']');
VarInfo* function_info = GetVarInfo(function_name);
if (function_info->kind == VarKind::kUnused) {
uint32_t index = module_builder_->AllocateIndirectFunctions(mask + 1);
if (index == std::numeric_limits<uint32_t>::max()) {
FAILn("Exceeded maximum function table size");
}
function_info->kind = VarKind::kTable;
function_info->mask = static_cast<int32_t>(mask);
function_info->index = module_builder_->AllocateIndirectFunctions(
static_cast<uint32_t>(mask + 1));
function_info->mask = mask;
function_info->index = index;
function_info->mutable_variable = false;
} else {
if (function_info->kind != VarKind::kTable) {
FAILn("Expected call table");
}
if (function_info->mask != static_cast<int32_t>(mask)) {
if (function_info->mask != mask) {
FAILn("Mask size mismatch");
}
}
......
......@@ -79,16 +79,14 @@ class AsmJsParser {
};
struct VarInfo {
AsmType* type;
WasmFunctionBuilder* function_builder;
FunctionImportInfo* import;
int32_t mask;
uint32_t index;
VarKind kind;
bool mutable_variable;
bool function_defined;
VarInfo();
AsmType* type = AsmType::None();
WasmFunctionBuilder* function_builder = nullptr;
FunctionImportInfo* import = nullptr;
uint32_t mask = 0;
uint32_t index = 0;
VarKind kind = VarKind::kUnused;
bool mutable_variable = true;
bool function_defined = false;
};
struct GlobalImport {
......
......@@ -271,9 +271,13 @@ uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
}
uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
uint32_t ret = static_cast<uint32_t>(indirect_functions_.size());
uint32_t index = static_cast<uint32_t>(indirect_functions_.size());
DCHECK_GE(FLAG_wasm_max_table_size, index);
if (count > FLAG_wasm_max_table_size - index) {
return std::numeric_limits<uint32_t>::max();
}
indirect_functions_.resize(indirect_functions_.size() + count);
return ret;
return index;
}
void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect,
......
// 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
function MODULE() {
"use asm";
function f() {
bogus_function_table[0 & LIMIT]();
}
return { f:f };
}
var bogus_function_table = [ Object ];
var test_set = [ 0x3fffffff, 0x7fffffff, 0xffffffff ];
for (var i = 0; i < test_set.length; ++i) {
bogus_function_table[i] = Object;
var src = MODULE.toString();
src = src.replace(/MODULE/g, "Module" + i);
src = src.replace(/LIMIT/g, test_set[i]);
var module = eval("(" + src + ")");
assertDoesNotThrow(module(this).f());
assertFalse(%IsAsmWasmCode(module));
}
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