From 9046d3bd912bf560bee830e43b872507c47a462b Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Fri, 2 Sep 2022 13:51:34 -0700 Subject: [PATCH] Throw an exception when a wasm trap is hit (#88) * Convert wasm traps to Dart exceptions * Fix analysis --- wasm/lib/src/runtime.g.dart | 5 ++--- wasm/lib/src/wasm_error.dart | 11 +++++++++++ wasm/test/test_shared.dart | 5 +++++ wasm/test/trap_test.dart | 33 +++++++++++++++++++++++++++++++ wasm/tool/runtime_template.dart.t | 5 ++--- 5 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 wasm/test/trap_test.dart diff --git a/wasm/lib/src/runtime.g.dart b/wasm/lib/src/runtime.g.dart index fffb946..63a0d51 100644 --- a/wasm/lib/src/runtime.g.dart +++ b/wasm/lib/src/runtime.g.dart @@ -597,9 +597,8 @@ class WasmRuntime { calloc.free(trapMessage); final entry = _traps.remove(message); if (entry == null) { - throw WasmError( - 'This case is not (yet) supported. Please file an issue on pkg:wasm.', - ); + // TODO(#87): Report a full stack trace to the user. + throw WasmException(message); } // ignore: only_throw_errors throw entry.exception; diff --git a/wasm/lib/src/wasm_error.dart b/wasm/lib/src/wasm_error.dart index f326aff..1a9e558 100644 --- a/wasm/lib/src/wasm_error.dart +++ b/wasm/lib/src/wasm_error.dart @@ -12,3 +12,14 @@ class WasmError extends Error { @override String toString() => 'WasmError: $message'; } + +/// Exception that wraps exceptions (traps) thrown inside wasm code. +class WasmException implements Exception { + /// Describes the nature of the exception. + final String message; + + WasmException(this.message); + + @override + String toString() => 'WasmException: $message'; +} diff --git a/wasm/test/test_shared.dart b/wasm/test/test_shared.dart index 33434a1..69f0a41 100644 --- a/wasm/test/test_shared.dart +++ b/wasm/test/test_shared.dart @@ -8,3 +8,8 @@ import 'package:wasm/src/wasm_error.dart'; Matcher throwsWasmError(Object messageMatcher) => throwsA( isA().having((p0) => p0.message, 'message', messageMatcher), ); + +Matcher throwsWasmException(Object messageMatcher) => throwsA( + isA() + .having((p0) => p0.message, 'message', messageMatcher), + ); diff --git a/wasm/test/trap_test.dart b/wasm/test/trap_test.dart new file mode 100644 index 0000000..26a5246 --- /dev/null +++ b/wasm/test/trap_test.dart @@ -0,0 +1,33 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Test that we can load a wasm module, find a function, and call it. +import 'dart:typed_data'; + +import 'package:test/test.dart'; +import 'package:wasm/wasm.dart'; + +import 'test_shared.dart'; + +void main() { + test('basics', () { + // (func $foo (export "foo") (type $t0) (unreachable)) + final data = Uint8List.fromList([ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, // + 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70, 0x01, 0x07, + 0x07, 0x05, 0x03, 0x01, 0x00, 0x11, 0x07, 0x10, 0x02, 0x03, 0x66, 0x6f, + 0x6f, 0x00, 0x00, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, + 0x0a, 0x05, 0x01, 0x03, 0x00, 0x00, 0x0b, 0x00, 0x2b, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x01, 0x06, 0x01, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x03, + 0x01, 0x00, 0x00, 0x04, 0x05, 0x01, 0x00, 0x02, 0x74, 0x30, 0x05, 0x05, + 0x01, 0x00, 0x02, 0x54, 0x30, 0x06, 0x09, 0x01, 0x00, 0x06, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, + ]); + + final inst = WasmModule(data).builder().build(); + final foo = inst.lookupFunction('foo'); + // ignore: unnecessary_lambdas + expect(() => foo(), throwsWasmException('unreachable')); + }); +} diff --git a/wasm/tool/runtime_template.dart.t b/wasm/tool/runtime_template.dart.t index cc295a9..0faac1f 100644 --- a/wasm/tool/runtime_template.dart.t +++ b/wasm/tool/runtime_template.dart.t @@ -118,9 +118,8 @@ class WasmRuntime { calloc.free(trapMessage); final entry = _traps.remove(message); if (entry == null) { - throw WasmError( - 'This case is not (yet) supported. Please file an issue on pkg:wasm.', - ); + // TODO(#87): Report a full stack trace to the user. + throw WasmException(message); } // ignore: only_throw_errors throw entry.exception;