diff options
-rw-r--r-- | std/wasi/snapshot_preview1.ts | 21 | ||||
-rw-r--r-- | std/wasi/snapshot_preview1_test.ts | 22 |
2 files changed, 40 insertions, 3 deletions
diff --git a/std/wasi/snapshot_preview1.ts b/std/wasi/snapshot_preview1.ts index 4c974fe1d..30756fe82 100644 --- a/std/wasi/snapshot_preview1.ts +++ b/std/wasi/snapshot_preview1.ts @@ -207,6 +207,10 @@ function syscall<T extends CallableFunction>(target: T) { try { return target(...args); } catch (err) { + if (err instanceof ExitStatus) { + throw err; + } + switch (err.name) { case "NotFound": return ERRNO_NOENT; @@ -266,15 +270,25 @@ interface FileDescriptor { entries?: Deno.DirEntry[]; } +export class ExitStatus { + code: number; + + constructor(code: number) { + this.code = code; + } +} + export interface ContextOptions { args?: string[]; env?: { [key: string]: string | undefined }; preopens?: { [key: string]: string }; + exitOnReturn?: boolean; } export default class Context { args: string[]; env: { [key: string]: string | undefined }; + exitOnReturn: boolean; memory: WebAssembly.Memory; fds: FileDescriptor[]; @@ -284,6 +298,7 @@ export default class Context { constructor(options: ContextOptions) { this.args = options.args ? options.args : []; this.env = options.env ? options.env : {}; + this.exitOnReturn = options.exitOnReturn ?? true; this.memory = null!; this.fds = [ @@ -1497,7 +1512,11 @@ export default class Context { "proc_exit": syscall(( rval: number, ): never => { - Deno.exit(rval); + if (this.exitOnReturn) { + Deno.exit(rval); + } + + throw new ExitStatus(rval); }), "proc_raise": syscall(( diff --git a/std/wasi/snapshot_preview1_test.ts b/std/wasi/snapshot_preview1_test.ts index d7e29e195..01b91bc3e 100644 --- a/std/wasi/snapshot_preview1_test.ts +++ b/std/wasi/snapshot_preview1_test.ts @@ -1,6 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import Context from "./snapshot_preview1.ts"; -import { assertEquals, assertThrows } from "../testing/asserts.ts"; +import Context, { ExitStatus } from "./snapshot_preview1.ts"; +import { assert, assertEquals, assertThrows } from "../testing/asserts.ts"; import { copy } from "../fs/mod.ts"; import * as path from "../path/mod.ts"; @@ -179,6 +179,24 @@ Deno.test("context_start", function () { TypeError, "export _start must be a function", ); + + try { + const context = new Context({ + exitOnReturn: false, + }); + context.start({ + exports: { + _start() { + const exit = context.exports["proc_exit"] as CallableFunction; + exit(0); + }, + memory: new WebAssembly.Memory({ initial: 1 }), + }, + }); + } catch (err) { + assert(err instanceof ExitStatus); + assertEquals(err.code, 0); + } }); Deno.test("context_initialize", function () { |