[wasm] Make a few more traps uncatchable

With the upcoming "exception handling" proposal, we have to ensure
that traps are not catchable. This patch adds missing "uncatchable"
annotations to traps in the C-API and table-related instructions.

Fixed: v8:11813
Change-Id: I7bbd5043ede58a5315bd5117eb496ed014e79e91
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2953160
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75082}
This commit is contained in:
Jakob Kummerow 2021-06-10 16:40:32 +02:00 committed by V8 LUCI CQ
parent 74dde2fce1
commit f1acce32c5
4 changed files with 35 additions and 6 deletions

View File

@ -85,7 +85,6 @@ class V8_NODISCARD ClearThreadInWasmScope {
}; };
Object ThrowWasmError(Isolate* isolate, MessageTemplate message) { Object ThrowWasmError(Isolate* isolate, MessageTemplate message) {
HandleScope scope(isolate);
Handle<JSObject> error_obj = isolate->factory()->NewWasmRuntimeError(message); Handle<JSObject> error_obj = isolate->factory()->NewWasmRuntimeError(message);
JSObject::AddProperty(isolate, error_obj, JSObject::AddProperty(isolate, error_obj,
isolate->factory()->wasm_uncatchable_symbol(), isolate->factory()->wasm_uncatchable_symbol(),
@ -133,6 +132,7 @@ RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) {
RUNTIME_FUNCTION(Runtime_ThrowWasmError) { RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
ClearThreadInWasmScope flag_scope(isolate); ClearThreadInWasmScope flag_scope(isolate);
HandleScope scope(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
CONVERT_SMI_ARG_CHECKED(message_id, 0); CONVERT_SMI_ARG_CHECKED(message_id, 0);
return ThrowWasmError(isolate, MessageTemplateFromInt(message_id)); return ThrowWasmError(isolate, MessageTemplateFromInt(message_id));
@ -381,9 +381,7 @@ Object ThrowTableOutOfBounds(Isolate* isolate,
if (isolate->context().is_null()) { if (isolate->context().is_null()) {
isolate->set_context(instance->native_context()); isolate->set_context(instance->native_context());
} }
Handle<Object> error_obj = isolate->factory()->NewWasmRuntimeError( return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
MessageTemplate::kWasmTrapTableOutOfBounds);
return isolate->Throw(*error_obj);
} }
} // namespace } // namespace

View File

@ -1006,8 +1006,11 @@ auto Trap::make(Store* store_abs, const Message& message) -> own<Trap> {
i::Isolate* isolate = store->i_isolate(); i::Isolate* isolate = store->i_isolate();
i::HandleScope handle_scope(isolate); i::HandleScope handle_scope(isolate);
i::Handle<i::String> string = VecToString(isolate, message); i::Handle<i::String> string = VecToString(isolate, message);
i::Handle<i::JSReceiver> exception = i::Handle<i::JSReceiver>::cast( i::Handle<i::JSObject> exception =
isolate->factory()->NewError(isolate->error_function(), string)); isolate->factory()->NewError(isolate->error_function(), string);
i::JSObject::AddProperty(isolate, exception,
isolate->factory()->wasm_uncatchable_symbol(),
isolate->factory()->true_value(), i::NONE);
return implement<Trap>::type::make(store, exception); return implement<Trap>::type::make(store, exception);
} }

View File

@ -531,6 +531,10 @@ void TestTrapNotCaught(byte* code, size_t code_size,
constexpr uint32_t kResultSuccess = 23; constexpr uint32_t kResultSuccess = 23;
constexpr uint32_t kResultCaught = 47; constexpr uint32_t kResultCaught = 47;
// Add an indirect function table.
const int kTableSize = 2;
r.builder().AddIndirectFunctionTable(nullptr, kTableSize);
// Build a trapping helper function. // Build a trapping helper function.
WasmFunctionCompiler& trap_func = r.NewFunction(sigs.i_ii()); WasmFunctionCompiler& trap_func = r.NewFunction(sigs.i_ii());
trap_func.Build(code, code + code_size); trap_func.Build(code, code + code_size);
@ -574,6 +578,17 @@ WASM_EXEC_TEST(TryCatchTrapRemByZero) {
TestTrapNotCaught(code, arraysize(code), execution_tier); TestTrapNotCaught(code, arraysize(code), execution_tier);
} }
WASM_EXEC_TEST(TryCatchTrapTableFill) {
EXPERIMENTAL_FLAG_SCOPE(reftypes);
int table_index = 0;
int length = 10; // OOB.
int start = 10; // OOB.
byte code[] = {WASM_TABLE_FILL(table_index, WASM_I32V(length),
WASM_REF_NULL(kFuncRefCode), WASM_I32V(start)),
WASM_I32V_1(42)};
TestTrapNotCaught(code, arraysize(code), execution_tier);
}
namespace { namespace {
// TODO(cleanup): Define in cctest.h and re-use where appropriate. // TODO(cleanup): Define in cctest.h and re-use where appropriate.
class IsolateScope { class IsolateScope {

View File

@ -35,6 +35,7 @@ void ExpectMessage(const char* expected, const Message& message) {
} // namespace } // namespace
TEST_F(WasmCapiTest, Traps) { TEST_F(WasmCapiTest, Traps) {
FLAG_experimental_wasm_eh = true;
ValueType i32_type[] = {kWasmI32}; ValueType i32_type[] = {kWasmI32};
FunctionSig sig(1, 0, i32_type); FunctionSig sig(1, 0, i32_type);
uint32_t callback_index = builder()->AddImport(CStrVector("callback"), &sig); uint32_t callback_index = builder()->AddImport(CStrVector("callback"), &sig);
@ -48,6 +49,11 @@ TEST_F(WasmCapiTest, Traps) {
byte code3[] = {WASM_I32V_3(0), WASM_UNREACHABLE, WASM_I32V_1(1)}; byte code3[] = {WASM_I32V_3(0), WASM_UNREACHABLE, WASM_I32V_1(1)};
AddFunction(code3, sizeof(code3), &sig); AddFunction(code3, sizeof(code3), &sig);
// Check that traps returned from a C callback are uncatchable in Wasm.
byte code4[] = {WASM_TRY_CATCH_ALL_T(
kWasmI32, WASM_CALL_FUNCTION0(callback_index), WASM_I32V(42))};
AddExportedFunction(CStrVector("uncatchable"), code4, sizeof(code4), &sig);
own<FuncType> func_type = own<FuncType> func_type =
FuncType::make(ownvec<ValType>::make(), FuncType::make(ownvec<ValType>::make(),
ownvec<ValType>::make(ValType::make(::wasm::I32))); ownvec<ValType>::make(ValType::make(::wasm::I32)));
@ -113,6 +119,13 @@ TEST_F(WasmCapiTest, Traps) {
EXPECT_EQ(2u, frame->func_index()); EXPECT_EQ(2u, frame->func_index());
EXPECT_EQ(1u, frame->func_offset()); EXPECT_EQ(1u, frame->func_offset());
EXPECT_EQ(func2_offset + frame->func_offset(), frame->module_offset()); EXPECT_EQ(func2_offset + frame->func_offset(), frame->module_offset());
Func* wasm_uncatchable_func = GetExportedFunction(2);
Val* args = nullptr;
Val results[1] = {Val(3.14)}; // Sentinel value.
own<Trap> uncatchable_trap = wasm_uncatchable_func->call(args, results);
EXPECT_NE(nullptr, uncatchable_trap.get());
EXPECT_EQ(::wasm::F64, results[0].kind());
} }
} // namespace wasm } // namespace wasm