typescript - Rust WebAssembly 自定义元素内存释放错误

标签 typescript rust shadow-dom wasm-bindgen

我的第一个 Rust 生成的 WASM 产生了以下错误,我不知道如何进行调试。

wasm-000650c2-23:340 Uncaught RuntimeError: memory access out of bounds
    at dlmalloc::dlmalloc::Dlmalloc::free::h36961b6fbcc40c05 (wasm-function[23]:670)
    at __rdl_dealloc (wasm-function[367]:8)
    at __rust_dealloc (wasm-function[360]:7)
    at alloc::alloc::dealloc::h90df92e1f727e726 (wasm-function[146]:100)
    at <alloc::alloc::Global as core::alloc::Alloc>::dealloc::h7f22ab187c7f5835 (wasm-function[194]:84)
    at <alloc::raw_vec::RawVec<T, A>>::dealloc_buffer::hdce29184552be976 (wasm-function[82]:231)
    at <alloc::raw_vec::RawVec<T, A> as core::ops::drop::Drop>::drop::h3910dccc175e44e6 (wasm-function[269]:38)
    at core::ptr::real_drop_in_place::hd26be2408c00ce9d (wasm-function[267]:38)
    at core::ptr::real_drop_in_place::h6acb013dbd13c114 (wasm-function[241]:50)
    at core::ptr::real_drop_in_place::hb270ba635548ab74 (wasm-function[69]:192)

上下文:最新的 Chrome,从 TypeScript 自定义元素调用的 Rust wasm-bindgen 代码,在影子 DOM 中的 Canvas 上运行。呈现到 Canvas 的数据来自 HTML5 AudioBuffer。所有 Rust 变量都在局部范围内。

如果文档中只出现一个实例,Web 组件将完美运行,但如果我进一步实例,则会像上面那样转储堆栈跟踪。代码运行没有任何其他问题。

我知道 Chrome 中存在显着的内存错误——它们看起来像这样吗,或者经验丰富的 rust/wasm 开发人员可以告诉我这是否异常?

js-sys = "0.3.19"
wasm-bindgen = "0.2.42"
wee_alloc = { version = "0.4.2", optional = true }
[dependencies.web-sys]
version = "0.3.4"

rust 代码很小,只将 AudioBuffer 的两个 channel 渲染到提供的 HTMLCanvasElement:

#[wasm_bindgen]
pub fn render(
    canvas: web_sys::HtmlCanvasElement,
    audio_buffer: &web_sys::AudioBuffer,
    stroke_style: &JsValue,
    line_width: f64,
    step_size: usize,
) { 
  // ...
    let mut channel_data: [Vec<f32>; 2] = unsafe { std::mem::uninitialized() }; // !
    for channel_number in 0..1 {
        channel_data[channel_number] = audio_buffer
            .get_channel_data(channel_number as u32)
            .unwrap();
    }
  // ...

我已经尝试注释掉功能,如果代码没有触及 Canvas 但执行了上述操作,我会收到错误消息。进行以下更改会导致简单的“out of wam memory”错误。音频文件为 1,200 k。

    let channel_data: [Vec<f32>; 2] = [
        audio_buffer.get_channel_data(0).unwrap(),
        audio_buffer.get_channel_data(1).unwrap()
    ];

编辑:后面的out of memory错误,对于上面正确的代码,真的让我很崩溃,但它实际上是一个Chrome bug .

最佳答案

你的问题是你创建了一大块未初始化的内存并且没有正确初始化它:

let mut channel_data: [Vec<f32>; 2] = unsafe { std::mem::uninitialized() };
for channel_number in 0..1 {
    channel_data[channel_number] = audio_buffer
        .get_channel_data(channel_number as u32) // no need for `as u32` here btw
        .unwrap();
}

Range s (又名 a..b )在 Rust 中是独有的。这意味着您的循环不会像您想象的那样迭代两次,而是只迭代一次并且您有一个未初始化的 Vec<f32>然后在放下它时会 panic。(请参阅 Matthieu M.'s answer 以获得正确的解释)

这里有几种可能性。

  1. 使用适当的范围,例如0..2
  2. 使用inclusive range 0..=1
  3. 不要使用不安全的结构,而是
    let mut channel_data: [Vec<f32>; 2] = Default::default()
    
    这将正确初始化两个 Vec秒。

有关如何初始化数组的更完整概述,请参阅 What is the proper way to initialize a fixed length array?

作为旁注:避免使用 unsafe ,尤其是如果您是 Rust 的新手。

关于typescript - Rust WebAssembly 自定义元素内存释放错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55741517/

相关文章:

rust - Cargo.toml 和 .cargo/config.toml 有什么区别

macros - 类型推断的奇怪宏行为

typescript - 如何让 npm 从 GitHub url 安装 typescript 依赖项?

angular - 如何将 Firebase 中的查询快照转换为不同的对象?

javascript - TypeScript 接口(interface)没有按我的预期工作

rust - 我可以获取字节数组并将其反序列化为结构吗?

javascript - 打印 typescript 编译器选项

javascript - 无法在 Chrome 37 中使用 Shadow DOM?

reactjs - React 是否扼杀了 Shadow-DOM 的概念

dart - 将 angular.dart 与 Bootstrap 一起使用会产生对象 #<Document> 没有方法 'getAttribute'