添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
耍酷的木瓜  ·  mysql ...·  10 月前    · 
火爆的草稿本  ·  智能搜索·  11 月前    · 
英勇无比的爆米花  ·  muduo笔记 ...·  1 年前    · 

Is there a way to register a handler of some form for JS to catch when a wasm module (index.html or webworker) has run out of memory and crashed ?

[The alternative is to send a heartbeat every second, but in that case it is not obvious how to tell if a webworker is busy crunching data or if it has crashed].

I am building my wasm32 with: cargo build --target=wasm32-unknown-unknown which, among other things, generates a *.js file which ends with:

async function init(input) {
    if (typeof input === 'undefined') {
        input = new URL('client_w_bg.wasm', import.meta.url);
    const imports = getImports();
    if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
        input = fetch(input);                 
    initMemory(imports);                        
    const { instance, module } = await load(await input, imports);
    return finalizeInit(instance, module);
export { initSync }
export default init;        

any intuition on whether this is achievable by wrapping around the existing tools, or if this would likely require modifying an auto generated *.js file?

I don't really understand the code snippet you posted here very well, but I would consider it a bug if the generated JS doesn't allow you to catch the exception in question.

I recommend that you try it. Write some Rust code that immediately fails, e.g.

let mut data = Vec::new();
data.resize(1000000000000, 42u8);

Then see what happens. My guess is that the location where you called the generated JS file will throw the exception I mentioned.

| ^^^^^^^^^^^^^^ = note: `#[deny(overflowing_literals)]` on by default = note: the literal `10_000_000_000` does not fit into the type `usize` whose range is `0..=4294967295`

steelmanning

        pub struct T {
            data: [u8; 100],}
        let mut data = Vec::<T>::new();
        data.reserve(1_000_000_000);

Here are the two errors I am getting in Chrome dev console right now:

client_w.js:474 panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:517:5 Stack: Error at imports.wbg.__wbg_new_693216e109162396 (http://localhost:8080/client_w.js:477:17) at console_error_panic_hook::Error::new::h8668ab84cb67189b (http://localhost:8080/client_w_bg.wasm:wasm-function[15376]:0x41a242) at console_error_panic_hook::hook_impl::hbfeb05050ef0e2aa (http://localhost:8080/client_w_bg.wasm:wasm-function[1791]:0x242799) at console_error_panic_hook::hook::h6a9927c1f0888f41 (http://localhost:8080/client_w_bg.wasm:wasm-function[16491]:0x429d6d) at core::ops::function::Fn::call::h167ccd9c6a07f6c8 (http://localhost:8080/client_w_bg.wasm:wasm-function[14229]:0x408382) at std::panicking::rust_panic_with_hook::h1c368a27f9b0afe1 (http://localhost:8080/client_w_bg.wasm:wasm-function[3903]:0x2e23f7) at std::panicking::begin_panic_handler::{{closure}}::h8e1f8b682ca33009 (http://localhost:8080/client_w_bg.wasm:wasm-function[6135]:0x348636) at std::sys_common::backtrace::__rust_end_short_backtrace::h7f7da41799766719 (http://localhost:8080/client_w_bg.wasm:wasm-function[19727]:0x44a9f1) at rust_begin_unwind (http://localhost:8080/client_w_bg.wasm:wasm-function[15646]:0x41e18f) at core::panicking::panic_fmt::hcdb13a4b2416cf82 (http://localhost:8080/client_w_bg.wasm:wasm-function[16345]:0x427de3) client_w_bg.wasm:0x44b77b Uncaught (in promise) RuntimeError: unreachable at __rust_start_panic (client_w_bg.wasm:0x44b77b) at rust_panic (client_w_bg.wasm:0x43fc20) at std::panicking::rust_panic_with_hook::h1c368a27f9b0afe1 (client_w_bg.wasm:0x2e2424) at std::panicking::begin_panic_handler::{{closure}}::h8e1f8b682ca33009 (client_w_bg.wasm:0x348636) at std::sys_common::backtrace::__rust_end_short_backtrace::h7f7da41799766719 (client_w_bg.wasm:0x44a9f1) at rust_begin_unwind (client_w_bg.wasm:0x41e18f) at core::panicking::panic_fmt::hcdb13a4b2416cf82 (client_w_bg.wasm:0x427de3) at alloc::raw_vec::capacity_overflow::h9e24c4d5bbf80bc3 (client_w_bg.wasm:0x427da3) at alloc::raw_vec::handle_reserve::h3bf48243ce6ec1b2 (client_w_bg.wasm:0x319568) at alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h96b1e49ef4ba0aad (client_w_bg.wasm:0x39431a)

analysis

The first one "panicked at 'capacity overflow'" definitely looks like a Rust exception.

I am not clear if the second "Uncaught (in promis) RuntimeError: unreachable" is a Rust or a JS exception.

For comparison, if I just type
throw "blah" into the Chrome dev console, the response is:

VM304:1 Uncaught blah
(anonymous) @ VM304:1

failing to catch it in JS land

I have the following JS fragment:

import init, * as wasm from "./client_w.js";
try {
        await init();
        var t2 = await wasm.Rust_Util.start_th_router()
    } catch (e) {
        console.log("JS caught error: ", e);

init is the JS function show in previous post, generated by the cargo build process

RustUtil is a Rust struct that looks like:

#[wasm_bindgen]
impl Rust_Util {
    pub async fn start_th_router() {
        Th_Router::start().await}

(Th_Router::start ends up doing the massive Vec).

I'm not sure why JS is not catching the exception right now. Possibly something to do with async (pure guess, no hard evidence).

Unfortunately, if the exception isn't available to be caught, then I do not know why.

I note that there's a difference between the following two ways of failing:

  • Overflow when computing the size to pass to the allocator.
  • The allocator is actually called, but returns a null pointer.
  • On platforms I am familiar with, the first option results in a panic, and the second option results in an unconditional abort. Supposedly panics always abort on WASM, so maybe they're indistinguishable from JS, but maybe they aren't.

    There's something else that gives me hope. The full error (which I failed to post last time since it involves clicking this little triangle error to expand) is:

    client_w_bg.wasm:0x44b77b Uncaught (in promise) RuntimeError: unreachable
        at __rust_start_panic (client_w_bg.wasm:0x44b77b)
        at rust_panic (client_w_bg.wasm:0x43fc20)
        at std::panicking::rust_panic_with_hook::h1c368a27f9b0afe1 (client_w_bg.wasm:0x2e2424)
        at std::panicking::begin_panic_handler::{{closure}}::h8e1f8b682ca33009 (client_w_bg.wasm:0x348636)
        at std::sys_common::backtrace::__rust_end_short_backtrace::h7f7da41799766719 (client_w_bg.wasm:0x44a9f1)
        at rust_begin_unwind (client_w_bg.wasm:0x41e18f)
        at core::panicking::panic_fmt::hcdb13a4b2416cf82 (client_w_bg.wasm:0x427de3)
        at alloc::raw_vec::capacity_overflow::h9e24c4d5bbf80bc3 (client_w_bg.wasm:0x427da3)
        at alloc::raw_vec::handle_reserve::h3bf48243ce6ec1b2 (client_w_bg.wasm:0x319568)
        at alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h96b1e49ef4ba0aad (client_w_bg.wasm:0x39431a)
    

    followed by the following part, which Chrome seems to not want to paste:

    $__rust_start_panic	@	client_w_bg.wasm:0x44b77b
    $rust_panic	@	client_w_bg.wasm:0x43fc20
    $std::panicking::rust_panic_with_hook::h1c368a27f9b0afe1	@	client_w_bg.wasm:0x2e2424
    $std::panicking::begin_panic_handler::{{closure}}::h8e1f8b682ca33009	@	client_w_bg.wasm:0x348636
    $std::sys_common::backtrace::__rust_end_short_backtrace::h7f7da41799766719	@	client_w_bg.wasm:0x44a9f1
    $rust_begin_unwind	@	client_w_bg.wasm:0x41e18f
    $core::panicking::panic_fmt::hcdb13a4b2416cf82	@	client_w_bg.wasm:0x427de3
    $alloc::raw_vec::capacity_overflow::h9e24c4d5bbf80bc3	@	client_w_bg.wasm:0x427da3
    $alloc::raw_vec::handle_reserve::h3bf48243ce6ec1b2	@	client_w_bg.wasm:0x319568
    $alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h96b1e49ef4ba0aad	@	client_w_bg.wasm:0x39431a
    $alloc::raw_vec::RawVec<T,A>::reserve::ha4813c8fa6d0fe56	@	client_w_bg.wasm:0x39b9e8
    $alloc::vec::Vec<T,A>::reserve::h8329cc9179c57cad	@	client_w_bg.wasm:0x405f32
    $x_client::th::th_router::th_router::<impl x_client::th::th_router::Th_Router>::start::{{closure}}::ha175e77530371d60	@	client_w_bg.wasm:0x1a83cb
    $<core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::hb15a1e5345c1f3de	@	client_w_bg.wasm:0x31a1c6
    $x_client::rust_util::Rust_Util::start_th_router::{{closure}}::h4387bae8d9a5b7f8	@	client_w_bg.wasm:0x227955
    $<core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::hb681e8281e88abfa	@	client_w_bg.wasm:0x31a286
    $x_client::rust_util::Rust_Util::start_th_router::{{closure}}::__wasm_bindgen_generated_Rust_Util_start_th_router__const::__wasm_bindgen_generated_Rust_Util_start_th_router::{{closure}}::h0052c0a885e5f1d2	@	client_w_bg.wasm:0x219492
    $<core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h06357a8143aaa79b	@	client_w_bg.wasm:0x2df111
    $wasm_bindgen_futures::future_to_promise::{{closure}}::{{closure}}::hac35c2ccc3cc4680	@	client_w_bg.wasm:0x192e47
    $<core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h8f7a545112f71a57	@	client_w_bg.wasm:0x31a106
    $wasm_bindgen_futures::task::singlethread::Task::run::h866c3547ae45c265	@	client_w_bg.wasm:0x211bd6
    $wasm_bindgen_futures::queue::QueueState::run_all::h0df0ec7a3376dcdc	@	client_w_bg.wasm:0x1e4b11
    $wasm_bindgen_futures::queue::Queue::new::{{closure}}::h4b48710e818f623b	@	client_w_bg.wasm:0x39caf4
    $<dyn core::ops::function::FnMut<(A,)>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::he4219956c4b8baba	@	client_w_bg.wasm:0x2fb75f
    __wbg_adapter_22	@	client_w.js:217
    real	@	client_w.js:202
    Promise.then (async)		
    imports.wbg.__wbg_then_18da6e5453572fc8	@	client_w.js:576
    $js_sys::Promise::then::ha706cc8b497d9959	@	client_w_bg.wasm:0x38fe61
    $wasm_bindgen_futures::queue::Queue::schedule_task::hb37c5e080a99d48f	@	client_w_bg.wasm:0x26e36b
    $wasm_bindgen_futures::task::singlethread::Task::spawn::{{closure}}::hf1401b79ff985fed	@	client_w_bg.wasm:0x41a3d0
    $std::thread::local::LocalKey<T>::try_with::h6d78ed4a0df90a96	@	client_w_bg.wasm:0x2bfa5f
    $std::thread::local::LocalKey<T>::with::h88e2d99c5d3190c6	@	client_w_bg.wasm:0x385e3e
    $wasm_bindgen_futures::task::singlethread::Task::spawn::h15abdf1670060700	@	client_w_bg.wasm:0x1c7751
    $wasm_bindgen_futures::spawn_local::hd875770121d54161	@	client_w_bg.wasm:0x2bb107
    $wasm_bindgen_futures::future_to_promise::{{closure}}::hb32ae5b744dbef9c	@	client_w_bg.wasm:0x2929f3
    $wasm_bindgen::convert::closures::invoke2_mut::he84dc53740f6e38c	@	client_w_bg.wasm:0x2e211f
    __wbg_adapter_79	@	client_w.js:282
    cb0	@	client_w.js:560
    imports.wbg.__wbg_new_52205195aa880fc2	@	client_w.js:565
    $js_sys::Promise::new::h33abaea97ab56066	@	client_w_bg.wasm:0x37f847
    $wasm_bindgen_futures::future_to_promise::h470c299cfcd8cbff	@	client_w_bg.wasm:0x2d687d
    $rust_util_start_th_router	@	client_w_bg.wasm:0x2dd286
    start_th_router	@	client_w.js:362
    (anonymous)	@	(index):27
    

    Now, if we look at the last two lines ,we see:

    start_th_router	@	client_w.js:362
    (anonymous)	@	(index):27
    

    (index) here refers to index.html

    client_w.js * @returns {Promise<void>} static start_th_router() { const ret = wasm.rust_util_start_th_router(); // ### LINE 362 ### return takeObject(ret); index.html
        try {
            await init();
            var t2 = await wasm.Rust_Util.start_th_router() // ### line 27 ###
        } catch (e) {
            console.log("JS caught error: ", e);
    analysis
    

    So we have identified how the calls are happening; the thrown exceptions even agrees with us in the call stack, but for whatever reason, we are not (yet) catching the exception.

    anon80458984:

    I am not clear if the second "Uncaught (in promis) RuntimeError: unreachable" is a Rust or a JS exception.

    This is the result of calling std::process::abort() (which on wasm codegens to the unreachable instruction), which Rust does on panics in case of -Cpanic=abort.

    Furthermore, because this is a Rust panic, does it mean we don't actually hit the wasm 4GB limit? I.e. is the allocator in generated Rust/wasm seeing that it is about to hit the 4GB limit -- and then deciding to abort before actually hitting the 4GB limit ? This might explain why this is a Rust panic/abort rather than a JS/Wasm error.

    anon80458984:

    Furthermore, because this is a Rust panic, does it mean we don't actually hit the wasm 4GB limit? I.e. is the allocator in generated Rust/wasm seeing that it is about to hit the 4GB limit -- and then deciding to abort before actually hitting the 4GB limit ? This might explain why this is a Rust panic/abort rather than a JS/Wasm error.

    The grow_memory instruction used for growing the heap may return an error in OOM cases. Rust catches this and prints an error if this happens before aborting. In your specific case I think it was a capacity overflow (which basically means attempting to allocate more than fits in a usize (or isize?)) rather than a failed memory allocation though.