Node.js v25.3.0 文档


WebAssembly 系统接口 (WASI)#>

【WebAssembly System Interface (WASI)】

稳定性: 1 - 实验性

node:wasi 模块目前尚未提供某些 WASI 运行时所具备的全面文件系统安全属性。未来可能会实现对安全文件系统沙箱的完全支持,也可能不会。在此期间,不要依赖它来运行不受信任的代码。

源代码: lib/wasi.js

WASI API 提供了 WebAssembly 系统接口 规范的实现。WASI 通过一系列类似 POSIX 的函数,使 WebAssembly 应用能够访问底层操作系统。

【The WASI API provides an implementation of the WebAssembly System Interface specification. WASI gives WebAssembly applications access to the underlying operating system via a collection of POSIX-like functions.】

import { readFile } from 'node:fs/promises';
import { WASI } from 'node:wasi';
import { argv, env } from 'node:process';

const wasi = new WASI({
  version: 'preview1',
  args: argv,
  env,
  preopens: {
    '/local': '/some/real/path/that/wasm/can/access',
  },
});

const wasm = await WebAssembly.compile(
  await readFile(new URL('./demo.wasm', import.meta.url)),
);
const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject());

wasi.start(instance);'use strict';
const { readFile } = require('node:fs/promises');
const { WASI } = require('node:wasi');
const { argv, env } = require('node:process');
const { join } = require('node:path');

const wasi = new WASI({
  version: 'preview1',
  args: argv,
  env,
  preopens: {
    '/local': '/some/real/path/that/wasm/can/access',
  },
});

(async () => {
  const wasm = await WebAssembly.compile(
    await readFile(join(__dirname, 'demo.wasm')),
  );
  const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject());

  wasi.start(instance);
})();

要运行上述示例,请创建一个名为 demo.wat 的新 WebAssembly 文本格式文件:

【To run the above example, create a new WebAssembly text format file named demo.wat:】

(module
    ;; Import the required fd_write WASI function which will write the given io vectors to stdout
    ;; The function signature for fd_write is:
    ;; (File Descriptor, *iovs, iovs_len, nwritten) -> Returns number of bytes written
    (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

    (memory 1)
    (export "memory" (memory 0))

    ;; Write 'hello world\n' to memory at an offset of 8 bytes
    ;; Note the trailing newline which is required for the text to appear
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; Creating a new io vector within linear memory
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - This is a pointer to the start of the 'hello world\n' string
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - The length of the 'hello world\n' string

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 for stdout
            (i32.const 0) ;; *iovs - The pointer to the iov array, which is stored at memory location 0
            (i32.const 1) ;; iovs_len - We're printing 1 string stored in an iov - so one.
            (i32.const 20) ;; nwritten - A place in memory to store the number of bytes written
        )
        drop ;; Discard the number of bytes written from the top of the stack
    )
) 

使用 wabt.wat 编译为 .wasm

【Use wabt to compile .wat to .wasm

wat2wasm demo.wat 

安全#>

【Security】

WASI 提供了一种基于能力的模型,通过该模型,应用可以获得自己的自定义 envpreopensstdinstdoutstderrexit 能力。

【WASI provides a capabilities-based model through which applications are provided their own custom env, preopens, stdin, stdout, stderr, and exit capabilities.】

当前的 Node.js 威胁模型并未提供像某些 WASI 运行时中那样的安全沙箱环境。

虽然能力特性受到支持,但它们并未在 Node.js 中形成安全模型。例如,文件系统沙箱可以通过各种技术被绕过。该项目正在探索未来是否可以添加这些安全保证。

【While the capability features are supported, they do not form a security model in Node.js. For example, the file system sandboxing can be escaped with various techniques. The project is exploring whether these security guarantees could be added in future.】

类:WASI#>

【Class: WASI

WASI 类提供了 WASI 系统调用 API 以及用于处理基于 WASI 的应用的额外便捷方法。每个 WASI 实例代表一个独立的环境。

【The WASI class provides the WASI system call API and additional convenience methods for working with WASI-based applications. Each WASI instance represents a distinct environment.】

new WASI([options])#>

  • options <Object>
    • args <Array> 一个字符串数组,WebAssembly 应用将把它们视为命令行参数。第一个参数是 WASI 命令本身的虚拟路径。默认值: []
    • env <Object> 一个类似于 process.env 的对象,WebAssembly 应用将其视作环境变量。默认值: {}
    • preopens <Object> 该对象表示 WebAssembly 应用的本地目录结构。preopens 的字符串键被视为文件系统中的目录。preopens 中对应的值是这些目录在主机上的真实路径。
    • returnOnExit <boolean> 默认情况下,当 WASI 应用调用 __wasi_proc_exit() 时,wasi.start() 会返回指定的退出代码,而不是终止进程。将此选项设置为 false 将导致 Node.js 进程以指定的退出代码退出。默认值: true
    • stdin <integer> 在 WebAssembly 应用中用作标准输入的文件描述符。默认值: 0
    • stdout <integer> 在 WebAssembly 应用中用作标准输出的文件描述符。默认值: 1
    • stderr <integer> 在 WebAssembly 应用中用作标准错误的文件描述符。默认值:2
    • version <string> 请求的 WASI 版本。目前唯一支持的版本是 unstablepreview1。此选项为必填项。

wasi.getImportObject()#>

返回一个可以传递给 WebAssembly.instantiate() 的导入对象,如果除了 WASI 提供的之外不需要其他 WASM 导入。

【Return an import object that can be passed to WebAssembly.instantiate() if no other WASM imports are needed beyond those provided by WASI.】

如果在构造函数中传入版本 unstable,它将返回:

【If version unstable was passed into the constructor it will return:】

{ wasi_unstable: wasi.wasiImport } 

如果在构造函数中传入了版本 preview1 或未指定版本,它将返回:

【If version preview1 was passed into the constructor or no version was specified it will return:】

{ wasi_snapshot_preview1: wasi.wasiImport } 

wasi.start(instance)#>

尝试通过调用其 _start() 导出将 instance 作为 WASI 命令开始执行。如果 instance 不包含 _start() 导出,或者 instance 包含 _initialize() 导出,则会抛出异常。

【Attempt to begin execution of instance as a WASI command by invoking its _start() export. If instance does not contain a _start() export, or if instance contains an _initialize() export, then an exception is thrown.】

start() 要求 instance 导出一个名为 memoryWebAssembly.Memory。如果 instance 没有 memory 导出,将抛出异常。

如果多次调用 start(),将抛出异常。

【If start() is called more than once, an exception is thrown.】

wasi.initialize(instance)#>

尝试通过调用其 _initialize() 导出将 instance 初始化为 WASI 反应器(如果存在)。如果 instance 包含 _start() 导出,则会抛出异常。

【Attempt to initialize instance as a WASI reactor by invoking its _initialize() export, if it is present. If instance contains a _start() export, then an exception is thrown.】

initialize() 要求 instance 导出一个名为 memoryWebAssembly.Memory。如果 instance 没有 memory 导出,将抛出异常。

如果多次调用 initialize(),将抛出异常。

【If initialize() is called more than once, an exception is thrown.】

wasi.finalizeBindings(instance[, options])#>

将 WASI 主机绑定设置到 instance,而无需调用 initialize()start()。当 WASI 模块在子线程中实例化以便在各线程间共享内存时,此方法非常有用。

【Set up WASI host bindings to instance without calling initialize() or start(). This method is useful when the WASI module is instantiated in child threads for sharing the memory across threads.】

finalizeBindings() 要求要么 instance 导出一个名为 memoryWebAssembly.Memory,要么用户在 options.memory 中指定一个 WebAssembly.Memory 对象。如果 memory 无效,将会抛出异常。

start()initialize() 会在内部调用 finalizeBindings()。如果 finalizeBindings() 被调用多次,将会抛出异常。

wasi.wasiImport#>

wasiImport 是一个实现了 WASI 系统调用 API 的对象。这个对象应在实例化 WebAssembly.Instance 时作为 wasi_snapshot_preview1 导入传入。

Node.js 中文网 - 粤ICP备13048890号