[wasm] Make exception creation non-observable by JS.

This fixes exception creation (by the WebAssembly throw operation) so
that it is not observable by JavaScript. Internal properties are now
stored with symbol names instead of string names, which also prevents
them from being accessed or monkey-patched directly by JavaScript.

R=clemensh@chromium.org
TEST=mjsunit/regress/wasm/regress-8094
BUG=v8:8094

Change-Id: I33cb27f4373114cd4db28d9aef23560093e55242
Reviewed-on: https://chromium-review.googlesource.com/1203951
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55602}
This commit is contained in:
Michael Starzinger 2018-09-04 11:51:28 +02:00 committed by Commit Bot
parent 175f2a6a6c
commit e8d79f070c
10 changed files with 119 additions and 79 deletions

View File

@ -273,6 +273,8 @@
V(sealed_symbol) \
V(stack_trace_symbol) \
V(strict_function_transition_symbol) \
V(wasm_exception_runtime_id_symbol) \
V(wasm_exception_values_symbol) \
V(uninitialized_symbol)
#define PUBLIC_SYMBOL_LIST(V) \

View File

@ -835,12 +835,32 @@ RUNTIME_FUNCTION(Runtime_IsWasmTrapHandlerEnabled) {
}
RUNTIME_FUNCTION(Runtime_GetWasmRecoveredTrapCount) {
HandleScope shs(isolate);
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
size_t trap_count = trap_handler::GetRecoveredTrapCount();
return *isolate->factory()->NewNumberFromSize(trap_count);
}
RUNTIME_FUNCTION(Runtime_GetWasmExceptionId) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, exception, 0);
RETURN_RESULT_OR_FAILURE(
isolate, JSReceiver::GetProperty(
isolate, exception,
isolate->factory()->wasm_exception_runtime_id_symbol()));
}
RUNTIME_FUNCTION(Runtime_GetWasmExceptionValues) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, exception, 0);
RETURN_RESULT_OR_FAILURE(
isolate, JSReceiver::GetProperty(
isolate, exception,
isolate->factory()->wasm_exception_values_symbol()));
}
namespace {
bool EnableWasmThreads(v8::Local<v8::Context> context) { return true; }

View File

@ -123,18 +123,18 @@ RUNTIME_FUNCTION(Runtime_WasmThrowCreate) {
static_cast<MessageTemplate::Template>(
MessageTemplate::kWasmExceptionError));
CONVERT_ARG_HANDLE_CHECKED(Smi, id, 0);
CHECK(!JSReceiver::SetProperty(isolate, exception,
isolate->factory()->InternalizeUtf8String(
wasm::WasmException::kRuntimeIdStr),
id, LanguageMode::kStrict)
CHECK(!JSReceiver::SetProperty(
isolate, exception,
isolate->factory()->wasm_exception_runtime_id_symbol(), id,
LanguageMode::kStrict)
.is_null());
CONVERT_SMI_ARG_CHECKED(size, 1);
Handle<JSTypedArray> values =
isolate->factory()->NewJSTypedArray(ElementsKind::UINT16_ELEMENTS, size);
CHECK(!JSReceiver::SetProperty(isolate, exception,
isolate->factory()->InternalizeUtf8String(
wasm::WasmException::kRuntimeValuesStr),
values, LanguageMode::kStrict)
CHECK(!JSReceiver::SetProperty(
isolate, exception,
isolate->factory()->wasm_exception_values_symbol(), values,
LanguageMode::kStrict)
.is_null());
return *exception;
}
@ -160,9 +160,9 @@ RUNTIME_FUNCTION(Runtime_WasmGetExceptionRuntimeId) {
if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate);
Handle<Object> tag;
if (JSReceiver::GetProperty(isolate, exception,
isolate->factory()->InternalizeUtf8String(
wasm::WasmException::kRuntimeIdStr))
if (JSReceiver::GetProperty(
isolate, exception,
isolate->factory()->wasm_exception_runtime_id_symbol())
.ToHandle(&tag)) {
if (tag->IsSmi()) {
return *tag;
@ -182,9 +182,9 @@ RUNTIME_FUNCTION(Runtime_WasmExceptionGetElement) {
if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate);
Handle<Object> values_obj;
if (JSReceiver::GetProperty(isolate, exception,
isolate->factory()->InternalizeUtf8String(
wasm::WasmException::kRuntimeValuesStr))
if (JSReceiver::GetProperty(
isolate, exception,
isolate->factory()->wasm_exception_values_symbol())
.ToHandle(&values_obj)) {
if (values_obj->IsJSTypedArray()) {
Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj);
@ -210,9 +210,9 @@ RUNTIME_FUNCTION(Runtime_WasmExceptionSetElement) {
if (!except_obj.is_null() && except_obj->IsJSReceiver()) {
Handle<JSReceiver> exception(JSReceiver::cast(*except_obj), isolate);
Handle<Object> values_obj;
if (JSReceiver::GetProperty(isolate, exception,
isolate->factory()->InternalizeUtf8String(
wasm::WasmException::kRuntimeValuesStr))
if (JSReceiver::GetProperty(
isolate, exception,
isolate->factory()->wasm_exception_values_symbol())
.ToHandle(&values_obj)) {
if (values_obj->IsJSTypedArray()) {
Handle<JSTypedArray> values = Handle<JSTypedArray>::cast(values_obj);

View File

@ -486,6 +486,8 @@ namespace internal {
F(GetDeoptCount, 1, 1) \
F(GetOptimizationStatus, -1, 1) \
F(GetUndetectable, 0, 1) \
F(GetWasmExceptionId, 1, 1) \
F(GetWasmExceptionValues, 1, 1) \
F(GetWasmRecoveredTrapCount, 0, 1) \
F(GlobalPrint, 1, 1) \
F(HasDictionaryElements, 1, 1) \

View File

@ -30,12 +30,6 @@ namespace wasm {
// static
const WasmExceptionSig WasmException::empty_sig_(0, 0, nullptr);
// static
constexpr const char* WasmException::kRuntimeIdStr;
// static
constexpr const char* WasmException::kRuntimeValuesStr;
WireBytesRef WasmModule::LookupFunctionName(const ModuleWireBytes& wire_bytes,
uint32_t function_index) const {
if (!function_names) {

View File

@ -81,10 +81,6 @@ struct WasmException {
const WasmExceptionSig* sig; // type signature of the exception.
// Used to hold data on runtime exceptions.
static constexpr const char* kRuntimeIdStr = "WasmExceptionRuntimeId";
static constexpr const char* kRuntimeValuesStr = "WasmExceptionValues";
private:
static const WasmExceptionSig empty_sig_;
};

View File

@ -0,0 +1,30 @@
// Copyright 2018 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: --expose-wasm --experimental-wasm-eh
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
// Instantiate a throwing module.
var builder = new WasmModuleBuilder();
builder.addException(kSig_v_v);
builder.addFunction("propel", kSig_v_v)
.addBody([kExprThrow, 0])
.exportFunc();
var instance = builder.instantiate();
// Catch the exception.
var exception;
try {
instance.exports.propel();
} catch (e) {
exception = e;
}
// Check that the exception is an instance of the correct error function and
// that no extraneous properties exist. Setting such properties could be
// observable by JavaScript and could break compatibility.
assertInstanceof(exception, WebAssembly.RuntimeError);
assertArrayEquals(["stack", "message"], Object.getOwnPropertyNames(exception));

View File

@ -2,11 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-wasm --experimental-wasm-eh
// Flags: --expose-wasm --experimental-wasm-eh --allow-natives-syntax
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
function assertWasmThrows(runtime_id, values, code) {
try {
if (typeof code === 'function') {
code();
} else {
eval(code);
}
} catch (e) {
assertInstanceof(e, WebAssembly.RuntimeError);
var e_runtime_id = %GetWasmExceptionId(e);
assertTrue(Number.isInteger(e_runtime_id));
assertEquals(e_runtime_id, runtime_id);
var e_values = %GetWasmExceptionValues(e);
assertArrayEquals(values, e_values);
return; // Success.
}
throw new MjsUnitAssertionError('Did not throw expected <' + runtime_id +
'> with values: ' + values);
}
// First we just test that "except_ref" local variables are allowed.
(function TestLocalExceptRef() {
let builder = new WasmModuleBuilder();

View File

@ -409,30 +409,6 @@ function assertTraps(trap, code) {
throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
}
function assertWasmThrows(runtime_id, values, code) {
try {
if (typeof code === 'function') {
code();
} else {
eval(code);
}
} catch (e) {
assertTrue(e instanceof WebAssembly.RuntimeError);
var e_runtime_id = e['WasmExceptionRuntimeId'];
assertEquals(e_runtime_id, runtime_id);
assertTrue(Number.isInteger(e_runtime_id));
var e_values = e['WasmExceptionValues'];
assertEquals(values.length, e_values.length);
for (i = 0; i < values.length; ++i) {
assertEquals(values[i], e_values[i]);
}
// Success.
return;
}
throw new MjsUnitAssertionError('Did not throw expected <' + runtime_id +
'> with values: ' + values);
}
function wasmI32Const(val) {
let bytes = [kExprI32Const];
for (let i = 0; i < 4; ++i) {

View File

@ -285,32 +285,32 @@ KNOWN_MAPS = {
("RO_SPACE", 0x04811): (173, "ArrayBoilerplateDescriptionMap"),
("RO_SPACE", 0x04b01): (161, "InterceptorInfoMap"),
("RO_SPACE", 0x04bf9): (169, "ScriptMap"),
("RO_SPACE", 0x09a81): (154, "AccessorInfoMap"),
("RO_SPACE", 0x09ad1): (153, "AccessCheckInfoMap"),
("RO_SPACE", 0x09b21): (155, "AccessorPairMap"),
("RO_SPACE", 0x09b71): (156, "AliasedArgumentsEntryMap"),
("RO_SPACE", 0x09bc1): (157, "AllocationMementoMap"),
("RO_SPACE", 0x09c11): (158, "AsyncGeneratorRequestMap"),
("RO_SPACE", 0x09c61): (159, "DebugInfoMap"),
("RO_SPACE", 0x09cb1): (160, "FunctionTemplateInfoMap"),
("RO_SPACE", 0x09d01): (162, "InterpreterDataMap"),
("RO_SPACE", 0x09d51): (163, "ModuleInfoEntryMap"),
("RO_SPACE", 0x09da1): (164, "ModuleMap"),
("RO_SPACE", 0x09df1): (165, "ObjectTemplateInfoMap"),
("RO_SPACE", 0x09e41): (166, "PromiseCapabilityMap"),
("RO_SPACE", 0x09e91): (167, "PromiseReactionMap"),
("RO_SPACE", 0x09ee1): (168, "PrototypeInfoMap"),
("RO_SPACE", 0x09f31): (170, "StackFrameInfoMap"),
("RO_SPACE", 0x09f81): (172, "Tuple3Map"),
("RO_SPACE", 0x09fd1): (174, "WasmDebugInfoMap"),
("RO_SPACE", 0x0a021): (175, "WasmExportedFunctionDataMap"),
("RO_SPACE", 0x0a071): (176, "CallableTaskMap"),
("RO_SPACE", 0x0a0c1): (177, "CallbackTaskMap"),
("RO_SPACE", 0x0a111): (178, "PromiseFulfillReactionJobTaskMap"),
("RO_SPACE", 0x0a161): (179, "PromiseRejectReactionJobTaskMap"),
("RO_SPACE", 0x0a1b1): (180, "PromiseResolveThenableJobTaskMap"),
("RO_SPACE", 0x0a201): (181, "AllocationSiteMap"),
("RO_SPACE", 0x0a251): (181, "AllocationSiteMap"),
("RO_SPACE", 0x09ac1): (154, "AccessorInfoMap"),
("RO_SPACE", 0x09b11): (153, "AccessCheckInfoMap"),
("RO_SPACE", 0x09b61): (155, "AccessorPairMap"),
("RO_SPACE", 0x09bb1): (156, "AliasedArgumentsEntryMap"),
("RO_SPACE", 0x09c01): (157, "AllocationMementoMap"),
("RO_SPACE", 0x09c51): (158, "AsyncGeneratorRequestMap"),
("RO_SPACE", 0x09ca1): (159, "DebugInfoMap"),
("RO_SPACE", 0x09cf1): (160, "FunctionTemplateInfoMap"),
("RO_SPACE", 0x09d41): (162, "InterpreterDataMap"),
("RO_SPACE", 0x09d91): (163, "ModuleInfoEntryMap"),
("RO_SPACE", 0x09de1): (164, "ModuleMap"),
("RO_SPACE", 0x09e31): (165, "ObjectTemplateInfoMap"),
("RO_SPACE", 0x09e81): (166, "PromiseCapabilityMap"),
("RO_SPACE", 0x09ed1): (167, "PromiseReactionMap"),
("RO_SPACE", 0x09f21): (168, "PrototypeInfoMap"),
("RO_SPACE", 0x09f71): (170, "StackFrameInfoMap"),
("RO_SPACE", 0x09fc1): (172, "Tuple3Map"),
("RO_SPACE", 0x0a011): (174, "WasmDebugInfoMap"),
("RO_SPACE", 0x0a061): (175, "WasmExportedFunctionDataMap"),
("RO_SPACE", 0x0a0b1): (176, "CallableTaskMap"),
("RO_SPACE", 0x0a101): (177, "CallbackTaskMap"),
("RO_SPACE", 0x0a151): (178, "PromiseFulfillReactionJobTaskMap"),
("RO_SPACE", 0x0a1a1): (179, "PromiseRejectReactionJobTaskMap"),
("RO_SPACE", 0x0a1f1): (180, "PromiseResolveThenableJobTaskMap"),
("RO_SPACE", 0x0a241): (181, "AllocationSiteMap"),
("RO_SPACE", 0x0a291): (181, "AllocationSiteMap"),
("MAP_SPACE", 0x02201): (1057, "ExternalMap"),
("MAP_SPACE", 0x02251): (1072, "JSMessageObjectMap"),
}