Index: src/asmjs/asm-typer.cc |
diff --git a/src/asmjs/asm-typer.cc b/src/asmjs/asm-typer.cc |
index 165ef9e148faf65e0b4e29701d7ba9b5edf97d07..1a3f932c93dc4eb7289c8a1ab6d69e3b588baf09 100644 |
--- a/src/asmjs/asm-typer.cc |
+++ b/src/asmjs/asm-typer.cc |
@@ -4,6 +4,7 @@ |
#include "src/asmjs/asm-typer.h" |
+#include <algorithm> |
#include <limits> |
#include <string> |
@@ -466,7 +467,89 @@ Assignment* ExtractInitializerExpression(Statement* statement) { |
} // namespace |
// 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) { |
+ SourceLayoutTracker source_layout; |
+ |
Scope* scope = fun->scope(); |
if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); |
if (!ValidAsmIdentifier(fun->name())) |
@@ -507,6 +590,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { |
if (use_asm_directive == nullptr || !IsUseAsmDirective(use_asm_directive)) { |
FAIL(fun, "Missing \"use asm\"."); |
} |
+ source_layout.AddUseAsm(*use_asm_directive); |
ReturnStatement* module_return = nullptr; |
// *VIOLATION* The spec states that globals should be followed by function |
@@ -520,6 +604,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { |
function_pointer_tables.push_back(assign); |
} else { |
RECURSE(ValidateGlobalDeclaration(assign)); |
+ source_layout.AddGlobal(*assign); |
} |
continue; |
} |
@@ -529,6 +614,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { |
FAIL(fun, "Multiple export statements."); |
} |
module_return = current_as_return; |
+ source_layout.AddExport(*module_return); |
continue; |
} |
@@ -542,12 +628,14 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { |
if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { |
RECURSE(ValidateFunction(fun_decl)); |
+ source_layout.AddFunction(*fun_decl); |
continue; |
} |
} |
for (auto* function_table : function_pointer_tables) { |
RECURSE(ValidateFunctionTable(function_table)); |
+ source_layout.AddTable(*function_table); |
} |
for (int ii = 0; ii < decls->length(); ++ii) { |
@@ -586,6 +674,10 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { |
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(); |
} |