Commit d50998c4 authored by jpp's avatar jpp Committed by Commit bot

V8. ASM-2-WASM. Enforces source code layout.

BUG= https://bugs.chromium.org/p/chromium/issues/detail?id=628450
BUG= https://bugs.chromium.org/p/v8/issues/detail?id=4203
TEST= cctest/asmjs/test-asm-typer.cc
TEST= mjsunit/wasm/*
LOG= N

Review-Url: https://codereview.chromium.org/2164273002
Cr-Commit-Position: refs/heads/master@{#37950}
parent 46e896e7
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/asmjs/asm-typer.h" #include "src/asmjs/asm-typer.h"
#include <algorithm>
#include <limits> #include <limits>
#include <string> #include <string>
...@@ -466,7 +467,89 @@ Assignment* ExtractInitializerExpression(Statement* statement) { ...@@ -466,7 +467,89 @@ Assignment* ExtractInitializerExpression(Statement* statement) {
} // namespace } // namespace
// 6.1 ValidateModule // 6.1 ValidateModule
namespace {
// SourceLayoutTracker keeps track of the start and end positions of each
// section in the asm.js source. The sections should not overlap, otherwise the
// asm.js source is invalid.
class SourceLayoutTracker {
public:
SourceLayoutTracker() = default;
bool IsValid() const {
const Section* kAllSections[] = {&use_asm_, &globals_, &functions_,
&tables_, &exports_};
for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) {
const auto& curr_section = *kAllSections[ii];
for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) {
if (curr_section.OverlapsWith(*kAllSections[jj])) {
return false;
}
}
}
return true;
}
void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); }
void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); }
void AddFunction(const AstNode& node) { functions_.AddNewElement(node); }
void AddTable(const AstNode& node) { tables_.AddNewElement(node); }
void AddExport(const AstNode& node) { exports_.AddNewElement(node); }
private:
class Section {
public:
Section() = default;
Section(const Section&) = default;
Section& operator=(const Section&) = default;
void AddNewElement(const AstNode& node) {
const int node_pos = node.position();
if (start_ == kNoSourcePosition) {
start_ = node_pos;
} else {
start_ = std::max(start_, node_pos);
}
if (end_ == kNoSourcePosition) {
end_ = node_pos;
} else {
end_ = std::max(end_, node_pos);
}
}
bool OverlapsWith(const Section& other) const {
if (start_ == kNoSourcePosition) {
DCHECK_EQ(end_, kNoSourcePosition);
return false;
}
if (other.start_ == kNoSourcePosition) {
DCHECK_EQ(other.end_, kNoSourcePosition);
return false;
}
return other.start_ < end_ || other.end_ < start_;
}
private:
int start_ = kNoSourcePosition;
int end_ = kNoSourcePosition;
};
Section use_asm_;
Section globals_;
Section functions_;
Section tables_;
Section exports_;
DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker);
};
} // namespace
AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
SourceLayoutTracker source_layout;
Scope* scope = fun->scope(); Scope* scope = fun->scope();
if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
if (!ValidAsmIdentifier(fun->name())) if (!ValidAsmIdentifier(fun->name()))
...@@ -507,6 +590,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { ...@@ -507,6 +590,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
if (use_asm_directive == nullptr || !IsUseAsmDirective(use_asm_directive)) { if (use_asm_directive == nullptr || !IsUseAsmDirective(use_asm_directive)) {
FAIL(fun, "Missing \"use asm\"."); FAIL(fun, "Missing \"use asm\".");
} }
source_layout.AddUseAsm(*use_asm_directive);
ReturnStatement* module_return = nullptr; ReturnStatement* module_return = nullptr;
// *VIOLATION* The spec states that globals should be followed by function // *VIOLATION* The spec states that globals should be followed by function
...@@ -520,6 +604,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { ...@@ -520,6 +604,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
function_pointer_tables.push_back(assign); function_pointer_tables.push_back(assign);
} else { } else {
RECURSE(ValidateGlobalDeclaration(assign)); RECURSE(ValidateGlobalDeclaration(assign));
source_layout.AddGlobal(*assign);
} }
continue; continue;
} }
...@@ -529,6 +614,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { ...@@ -529,6 +614,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
FAIL(fun, "Multiple export statements."); FAIL(fun, "Multiple export statements.");
} }
module_return = current_as_return; module_return = current_as_return;
source_layout.AddExport(*module_return);
continue; continue;
} }
...@@ -542,12 +628,14 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { ...@@ -542,12 +628,14 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
RECURSE(ValidateFunction(fun_decl)); RECURSE(ValidateFunction(fun_decl));
source_layout.AddFunction(*fun_decl);
continue; continue;
} }
} }
for (auto* function_table : function_pointer_tables) { for (auto* function_table : function_pointer_tables) {
RECURSE(ValidateFunctionTable(function_table)); RECURSE(ValidateFunctionTable(function_table));
source_layout.AddTable(*function_table);
} }
for (int ii = 0; ii < decls->length(); ++ii) { for (int ii = 0; ii < decls->length(); ++ii) {
...@@ -586,6 +674,10 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { ...@@ -586,6 +674,10 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
RECURSE(ValidateExport(module_return)); RECURSE(ValidateExport(module_return));
if (!source_layout.IsValid()) {
FAIL(fun, "Invalid asm.js source code layout.");
}
return AsmType::Int(); // Any type that is not AsmType::None(); return AsmType::Int(); // Any type that is not AsmType::None();
} }
......
...@@ -1797,4 +1797,113 @@ TEST(CannotReferenceModuleName) { ...@@ -1797,4 +1797,113 @@ TEST(CannotReferenceModuleName) {
} }
} }
TEST(InvalidSourceLayout) {
const char* kTests[] = {
"function asm() {\n"
" 'use asm';\n"
" function f() {}\n"
" var v = 0;\n"
" var v_v = [f];\n"
" return f;\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" function f() {}\n"
" var v_v = [f];\n"
" var v = 0;\n"
" return f;\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" function f() {}\n"
" var v_v = [f];\n"
" return f;\n"
" var v = 0;\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" var v = 0;\n"
" var v_v = [f];\n"
" function f() {}\n"
" return f;\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" var v = 0;\n"
" var v_v = [f];\n"
" return f;\n"
" function f() {}\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" var v = 0;\n"
" function f() {}\n"
" return f;\n"
" var v_v = [f];\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" var v = 0;\n"
" function f() {}\n"
" var v1 = 0;\n"
" var v_v = [f];\n"
" return f;\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" var v = 0;\n"
" function f() {}\n"
" var v_v = [f];\n"
" var v1 = 0;\n"
" return f;\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" var v = 0;\n"
" function f() {}\n"
" var v_v = [f];\n"
" return f;\n"
" var v1 = 0;\n"
"}",
"function asm() {\n"
" function f() {}\n"
" 'use asm';\n"
" var v_v = [f];\n"
" return f;\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" return f;\n"
" var v = 0;\n"
" function f() {}\n"
" var v_v = [f];\n"
"}",
"function asm() {\n"
" 'use asm';\n"
" return f;\n"
" function f() {}\n"
"}",
"function __f_59() {\n"
" 'use asm';\n"
" function __f_110() {\n"
" return 71;\n"
" }\n"
" function __f_21() {\n"
" var __v_38 = 0;\n"
" return __v_23[__v_38&0]() | 0;\n"
" }\n"
" return {__f_21:__f_21};\n"
" var __v_23 = [__f_110];\n"
"}",
};
for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
if (!ValidationOf(Module(kTests[ii]))
->FailsWithMessage("Invalid asm.js source code layout")) {
std::cerr << "Test:\n" << kTests[ii];
CHECK(false);
}
}
}
} // namespace } // namespace
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