[wasm][asm.js] Ensure final validation phase runs.

Asm.js modules missing exports fail to run the last phase of
validation. Adding an explicit check for this.

BUG=676573
R=titzer@chromium.org,aseemgarg@chromium.org

Review-Url: https://codereview.chromium.org/2620893002
Cr-Commit-Position: refs/heads/master@{#42191}
This commit is contained in:
bradnelson 2017-01-10 09:47:21 -08:00 committed by Commit bot
parent e8188a2d99
commit b1cfa6448c
4 changed files with 55 additions and 12 deletions

View File

@ -20,25 +20,31 @@
#include "src/globals.h" #include "src/globals.h"
#include "src/messages.h" #include "src/messages.h"
#include "src/utils.h" #include "src/utils.h"
#include "src/vector.h"
#define FAIL_LOCATION(location, msg) \ #define FAIL_LOCATION_RAW(location, msg) \
do { \ do { \
Handle<String> message(isolate_->factory()->InternalizeOneByteString( \ Handle<String> message( \
STATIC_CHAR_VECTOR(msg))); \ isolate_->factory()->InternalizeOneByteString(msg)); \
error_message_ = MessageHandler::MakeMessageObject( \ error_message_ = MessageHandler::MakeMessageObject( \
isolate_, MessageTemplate::kAsmJsInvalid, (location), message, \ isolate_, MessageTemplate::kAsmJsInvalid, (location), message, \
Handle<JSArray>::null()); \ Handle<JSArray>::null()); \
error_message_->set_error_level(v8::Isolate::kMessageWarning); \ error_message_->set_error_level(v8::Isolate::kMessageWarning); \
message_location_ = *(location); \ message_location_ = *(location); \
return AsmType::None(); \ return AsmType::None(); \
} while (false) } while (false)
#define FAIL(node, msg) \ #define FAIL_RAW(node, msg) \
do { \ do { \
MessageLocation location(script_, node->position(), node->position()); \ MessageLocation location(script_, node->position(), node->position()); \
FAIL_LOCATION(&location, msg); \ FAIL_LOCATION_RAW(&location, msg); \
} while (false) } while (false)
#define FAIL_LOCATION(location, msg) \
FAIL_LOCATION_RAW(location, STATIC_CHAR_VECTOR(msg))
#define FAIL(node, msg) FAIL_RAW(node, STATIC_CHAR_VECTOR(msg))
#define RECURSE(call) \ #define RECURSE(call) \
do { \ do { \
if (GetCurrentStackPosition() < stack_limit_) { \ if (GetCurrentStackPosition() < stack_limit_) { \
@ -530,6 +536,10 @@ AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
return member; return member;
} }
AsmType* AsmTyper::FailWithMessage(const char* text) {
FAIL_RAW(root_, OneByteVector(text));
}
bool AsmTyper::Validate() { bool AsmTyper::Validate() {
return ValidateBeforeFunctionsPhase() && return ValidateBeforeFunctionsPhase() &&
!AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) && !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) &&

View File

@ -86,6 +86,10 @@ class AsmTyper final {
AsmType* TypeOf(Variable* v) const; AsmType* TypeOf(Variable* v) const;
StandardMember VariableAsStandardMember(Variable* var); StandardMember VariableAsStandardMember(Variable* var);
// Allow the asm-wasm-builder to trigger failures (for interleaved
// validating).
AsmType* FailWithMessage(const char* text);
typedef std::unordered_set<StandardMember, std::hash<int> > StdlibSet; typedef std::unordered_set<StandardMember, std::hash<int> > StdlibSet;
StdlibSet StdlibUses() const { return stdlib_uses_; } StdlibSet StdlibUses() const { return stdlib_uses_; }

View File

@ -67,6 +67,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
script_(script), script_(script),
typer_(typer), typer_(typer),
typer_failed_(false), typer_failed_(false),
typer_finished_(false),
breakable_blocks_(zone), breakable_blocks_(zone),
foreign_variables_(zone), foreign_variables_(zone),
init_function_(nullptr), init_function_(nullptr),
@ -122,6 +123,10 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
if (HasStackOverflow()) { if (HasStackOverflow()) {
return false; return false;
} }
if (!typer_finished_) {
typer_->FailWithMessage("Module missing export section.");
typer_failed_ = true;
}
if (typer_failed_) { if (typer_failed_) {
return false; return false;
} }
@ -322,10 +327,16 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
void VisitReturnStatement(ReturnStatement* stmt) { void VisitReturnStatement(ReturnStatement* stmt) {
if (scope_ == kModuleScope) { if (scope_ == kModuleScope) {
if (typer_finished_) {
typer_->FailWithMessage("Module has multiple returns.");
typer_failed_ = true;
return;
}
if (!typer_->ValidateAfterFunctionsPhase()) { if (!typer_->ValidateAfterFunctionsPhase()) {
typer_failed_ = true; typer_failed_ = true;
return; return;
} }
typer_finished_ = true;
scope_ = kExportScope; scope_ = kExportScope;
RECURSE(Visit(stmt->expression())); RECURSE(Visit(stmt->expression()));
scope_ = kModuleScope; scope_ = kModuleScope;
@ -1947,6 +1958,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
Handle<Script> script_; Handle<Script> script_;
AsmTyper* typer_; AsmTyper* typer_;
bool typer_failed_; bool typer_failed_;
bool typer_finished_;
ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_; ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
ZoneVector<ForeignVariable> foreign_variables_; ZoneVector<ForeignVariable> foreign_variables_;
WasmFunctionBuilder* init_function_; WasmFunctionBuilder* init_function_;

View File

@ -0,0 +1,17 @@
// 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.
function baz() {
"use asm";
}
function B(stdlib, env) {
"use asm";
var x = env.foo | 0;
}
var bar = {
get foo() {
}
};
bar.__defineGetter__('foo', function() { return baz(); });
B(this, bar);