You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebAssembly:Rust与JavaScript宿主间内存地址传递问题

WASM模块与JS宿主间字符串传递的指针映射问题解决

问题背景

通过cargo build --target wasm32-unknown-unknown --release编译Rust代码到WASM,测试WASM与JS宿主的字符串/二进制内容传递。Rust侧定义静态缓冲区并调用外部read函数填充;JS侧实现read分块传递字符串,但发现Rust传入的指针不在WASM内存范围内,无法正确写入数据。

核心原因

你在JS中手动创建了独立的WebAssembly.Memory实例,但Rust编译的WASM模块默认会自行创建内存空间,导致JS操作的内存与Rust实际使用的内存完全隔离,指针自然无法对应。

解决方案

1. 让Rust导入JS提供的共享内存

修改Rust代码,显式声明导入JS提供的内存,确保双方共享同一块地址空间:

// 显式导入JS侧提供的内存实例
#[link(import_name = "memory")]
extern "C" {
    static mut memory: [u8; 0];
}

extern "C" {
    fn read(ptr: *mut u8, len: u32) -> u32;
}

const BUF_LEN: usize = 4;
static mut BUF: [u8; BUF_LEN] = [0u8; BUF_LEN];

#[no_mangle]
pub unsafe extern "C" fn parse() -> f64 {
    let mut result = String::new();
    while {
        let ptr = BUF.as_mut_ptr();
        let n = read(ptr, BUF_LEN as u32) as usize;
        if n == 0 {
            break; // 无更多字节,终止循环
        }
        result.push_str(std::str::from_utf8_unchecked(&BUF[0..n]));
        n == BUF_LEN
    } { }
    
    result.parse().unwrap()
}

2. 修正JS侧的字节传递逻辑

修复字节切片错误,保留未传递的剩余字节,并处理消息耗尽的边界情况:

const module = new WebAssembly.Module(bin);
const memory = new WebAssembly.Memory({ initial: 2 }); // 1页=64KB,2页足够当前测试

let bytes = new Uint8Array([]);
const messages = [
    "123.4",
    "1234256.6"
];
const importObject = {
    env: {
        memory,
        read(ptr, len) {
            if (bytes.byteLength === 0) {
                // 加载新消息
                const encoder = new TextEncoder();
                const value = messages.pop();
                if (!value) return 0; // 无更多消息,返回0表示结束
                bytes = encoder.encode(value);
            }
            
            const written = Math.min(bytes.byteLength, len);
            // 将字节写入WASM内存的指定偏移位置
            const view = new Uint8Array(memory.buffer, ptr, written);
            view.set(bytes.subarray(0, written));
            // 保留剩余未传递的字节
            bytes = bytes.subarray(written);
            
            return written;
        }
    }
};

const instance = new WebAssembly.Instance(module, importObject);
const { parse } = instance.exports;
console.log(parse()); // 输出1234256.6
console.log(parse()); // 输出123.4

关键细节说明

  • 共享内存对齐:Rust通过#[link(import_name = "memory")]导入JS内存实例,确保双方地址空间完全一致,Rust传递的指针直接对应WASM内存的偏移量。
  • 字节切片修正:使用subarray代替slice,避免创建新数组,正确保留未传递的剩余字节,确保循环能正常退出。
  • 结束信号机制:无消息时返回0,Rust侧检测到0后终止读取循环,避免无限等待。

内容的提问来源于stack exchange,提问作者Bartosz Sypytkowski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:45:10