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

[asm.js] Make validation of stdlib uses non-observable.

This makes sure that the checking of stdlib values during module
instantiation is non-observable. It is needed to prevent observable
double evaluation of the involved property loads in case of failures
during instantiation and also fixes some issues with exceptions
happening during property loads.

R=clemensh@chromium.org
TEST=mjsunit/asm/asm-stdlib
BUG=v8:6297

Change-Id: I1d0c371e51bee8186d14fa794fb3f9b7f67e5944
Reviewed-on: https://chromium-review.googlesource.com/501887Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45237}
parent 55a610ba
......@@ -40,24 +40,13 @@ enum WasmDataEntries {
Handle<Object> StdlibMathMember(Isolate* isolate, Handle<JSReceiver> stdlib,
Handle<Name> name) {
if (stdlib.is_null()) {
return Handle<Object>();
}
Handle<Name> math_name(
isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Math")));
MaybeHandle<Object> maybe_math = Object::GetProperty(stdlib, math_name);
if (maybe_math.is_null()) {
return Handle<Object>();
}
Handle<Object> math = maybe_math.ToHandleChecked();
if (!math->IsJSReceiver()) {
return Handle<Object>();
}
MaybeHandle<Object> maybe_value = Object::GetProperty(math, name);
if (maybe_value.is_null()) {
return Handle<Object>();
}
return maybe_value.ToHandleChecked();
Handle<Object> math = JSReceiver::GetDataProperty(stdlib, math_name);
if (!math->IsJSReceiver()) return isolate->factory()->undefined_value();
Handle<JSReceiver> math_receiver = Handle<JSReceiver>::cast(math);
Handle<Object> value = JSReceiver::GetDataProperty(math_receiver, name);
return value;
}
bool IsStdlibMemberValid(Isolate* isolate, Handle<JSReceiver> stdlib,
......@@ -65,29 +54,13 @@ bool IsStdlibMemberValid(Isolate* isolate, Handle<JSReceiver> stdlib,
bool* is_typed_array) {
switch (member) {
case wasm::AsmJsParser::StandardMember::kInfinity: {
if (stdlib.is_null()) {
return false;
}
Handle<Name> name(isolate->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("Infinity")));
MaybeHandle<Object> maybe_value = Object::GetProperty(stdlib, name);
if (maybe_value.is_null()) {
return false;
}
Handle<Object> value = maybe_value.ToHandleChecked();
Handle<Name> name = isolate->factory()->infinity_string();
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
return value->IsNumber() && std::isinf(value->Number());
}
case wasm::AsmJsParser::StandardMember::kNaN: {
if (stdlib.is_null()) {
return false;
}
Handle<Name> name(isolate->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("NaN")));
MaybeHandle<Object> maybe_value = Object::GetProperty(stdlib, name);
if (maybe_value.is_null()) {
return false;
}
Handle<Object> value = maybe_value.ToHandleChecked();
Handle<Name> name = isolate->factory()->nan_string();
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name);
return value->IsNaN();
}
#define STDLIB_MATH_FUNC(fname, FName, ignore1, ignore2) \
......@@ -95,10 +68,8 @@ bool IsStdlibMemberValid(Isolate* isolate, Handle<JSReceiver> stdlib,
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
STATIC_CHAR_VECTOR(#fname))); \
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
if (value.is_null() || !value->IsJSFunction()) { \
return false; \
} \
Handle<JSFunction> func(JSFunction::cast(*value)); \
if (!value->IsJSFunction()) return false; \
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
return func->shared()->code() == \
isolate->builtins()->builtin(Builtins::kMath##FName); \
}
......@@ -109,26 +80,19 @@ bool IsStdlibMemberValid(Isolate* isolate, Handle<JSReceiver> stdlib,
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
STATIC_CHAR_VECTOR(#cname))); \
Handle<Object> value = StdlibMathMember(isolate, stdlib, name); \
return !value.is_null() && value->IsNumber() && \
value->Number() == const_value; \
return value->IsNumber() && value->Number() == const_value; \
}
STDLIB_MATH_VALUE_LIST(STDLIB_MATH_CONST)
#undef STDLIB_MATH_CONST
#define STDLIB_ARRAY_TYPE(fname, FName) \
case wasm::AsmJsParser::StandardMember::k##FName: { \
*is_typed_array = true; \
if (stdlib.is_null()) { \
return false; \
} \
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
STATIC_CHAR_VECTOR(#FName))); \
Handle<Object> value; \
MaybeHandle<Object> maybe_value = Object::GetProperty(stdlib, name); \
if (!maybe_value.ToHandle(&value) || !value->IsJSFunction()) { \
return false; \
} \
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
return func.is_identical_to(isolate->fname()); \
#define STDLIB_ARRAY_TYPE(fname, FName) \
case wasm::AsmJsParser::StandardMember::k##FName: { \
*is_typed_array = true; \
Handle<Name> name(isolate->factory()->InternalizeOneByteString( \
STATIC_CHAR_VECTOR(#FName))); \
Handle<Object> value = JSReceiver::GetDataProperty(stdlib, name); \
if (!value->IsJSFunction()) return false; \
Handle<JSFunction> func = Handle<JSFunction>::cast(value); \
return func.is_identical_to(isolate->fname()); \
}
STDLIB_ARRAY_TYPE(int8_array_fun, Int8Array)
STDLIB_ARRAY_TYPE(uint8_array_fun, Uint8Array)
......@@ -261,6 +225,7 @@ MaybeHandle<Object> AsmJs::InstantiateAsmWasm(Isolate* isolate,
// Check that all used stdlib members are valid.
bool stdlib_use_of_typed_array_present = false;
for (int i = 0; i < stdlib_uses->length(); ++i) {
if (stdlib.is_null()) return MaybeHandle<Object>();
int member_id = Smi::cast(stdlib_uses->get(i))->value();
wasm::AsmJsParser::StandardMember member =
static_cast<wasm::AsmJsParser::StandardMember>(member_id);
......
// 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 FailProxyAsStdlib() {
// Test that passing a proxy as "stdlib" will cause module instantiation to
// fail while still only triggering one observable property load.
function Module(stdlib, foreign, heap) {
"use asm";
var a = stdlib.Math.PI;
function f() { return a }
return { f:f };
}
var trap_was_called = 0;
var proxy = new Proxy(this, { get:function(target, property, receiver) {
trap_was_called++;
if (property == "Math") return { PI:23 };
return Reflect.get(target, property, receiver);
}});
var m = Module(proxy);
assertFalse(%IsAsmWasmCode(Module));
assertEquals(1, trap_was_called);
assertEquals(23, m.f());
})();
(function FailGetterInStdlib() {
// Test that accessors as part of "stdlib" will cause module instantiation to
// fail while still only triggering one observable property load.
function Module(stdlib, foreign, heap) {
"use asm";
var a = new stdlib.Int8Array(heap);
function f() { return a[0] | 0 }
return { f:f };
}
var trap_was_called = 0;
var observer = { get Int8Array() {
trap_was_called++;
return function() { return [ 23 ] };
}};
var m = Module(observer);
assertFalse(%IsAsmWasmCode(Module));
assertEquals(1, trap_was_called);
assertEquals(23, m.f());
})();
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