Skip to content

Does not die on error when big WASM module is loaded #3498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dyedgreen opened this issue Dec 14, 2019 · 8 comments
Closed

Does not die on error when big WASM module is loaded #3498

dyedgreen opened this issue Dec 14, 2019 · 8 comments
Labels
bug Something isn't working correctly

Comments

@dyedgreen
Copy link
Contributor

There seems to be an issue where Deno does not exit correctly if an uncaught exception occurs and a big WASM module was imported.

This seems to happen for modules around 100K and bigger (from testing on my machine, vary the 10000 in for loop to get different size binary).

Note: I ran across the issue while working on: https://github.com/dyedgreen/deno-sqlite, which uses a binary of around 1MB.

Steps to reproduce:

  1. Build big WASM file:
deno --allow-write gen_big.js
clang --target=wasm32 --no-standard-libraries -Wl,--no-entry -nostartfiles -O0 -o big.wasm big.c
  1. Run deno big.js

Needed files

// gen_big.js

const prefix = "test";
const str = "int ?(a, b) { return a+b; }";

const lines = [];
const main = ["int a = 0;"];
for (let i = 0; i < 10000; i ++) {
  lines.push(str.replace("?", prefix.concat(i)));
  main.push("a = " + prefix.concat(i) + "(a, b);");
  if (i % 1000 === 0)
    console.log(i);
}
main.push("return a;");
const total = lines.join("\n") + "\n\n" + `int __attribute__((used)) __attribute__ ((visibility ("default"))) add(int b) {\n${main.join("\n")}\n};\n`;
await Deno.writeFile("big.c", new TextEncoder().encode(total));
// big.js

import * as mod from "./big.wasm";

throw new Error("Does not die :(");
@dyedgreen dyedgreen changed the title Does not die when big WASM module is loaded Does not die on error when big WASM module is loaded Dec 14, 2019
@ry ry added the bug Something isn't working correctly label Dec 14, 2019
@kevinkassimo
Copy link
Contributor

Worth noting this is not limited to WASM import syntax, but also normal WebAssembly.compile. The following also stucks forever

const mod = await WebAssembly.compile(Deno.readFileSync("./big.wasm"));
console.log(mod);
throw new Error("Does not die :(");

Execution output:

Module {}
error: Uncaught Error: Does not die :(
► file:///Users/kun/Projects/Deno/test/wasm_bug/small.js:9:7

9 throw new Error("Does not die :(");
        ^

    at file:///Users/kun/Projects/Deno/test/wasm_bug/small.js:9:7

# STUCK FOREVER

@kevinkassimo
Copy link
Contributor

kevinkassimo commented Dec 15, 2019

Fun fact: it is stuck at

pub fn print_err_and_exit(err: ErrBox) {
  eprintln!("{}", err.to_string());
  std::process::exit(1); // <-- ! This line
}

It turns out that using libc::_exit(1) instead will allow immediate exit. Maybe there is some atexit handlers blocking or some flushing problem.

On macOS, here seems to be a __psynch_cvwait that stuck forever in a thread other than main thread, some pthread_mutex_lock is blocked.

Also investigating through __cxa_finalize_ranges to see which atexit handlers are executed.

Likely stuck halfway during some destructor, possibly one of them is calling pthread_join on main thread (while other thread block-waits). (Confirmed that this (symbol name _pthread_join on macOS) is the last call before main thread goes into infinite sleep)

@kevinkassimo
Copy link
Contributor

kevinkassimo commented Dec 15, 2019

Dump backtrace of where this pthread_join is called:

* thread #2, name = 'tokio-runtime-worker-0', stop reason = breakpoint 1.1
  * frame #0: 0x00007fff675876f8 libsystem_pthread.dylib`pthread_join
    frame #1: 0x00000001024a3938 deno`::~WorkerThread() [inlined] ~WorkerThread at default-worker-threads-task-runner.cc:79:65 [opt]
    frame #2: 0x00000001024a3929 deno`::~WorkerThread() [inlined] ~WorkerThread at default-worker-threads-task-runner.cc:79 [opt]
    frame #3: 0x00000001024a3929 deno`::~WorkerThread() at default-worker-threads-task-runner.cc:79 [opt]
    frame #4: 0x00000001024a3760 deno`::Terminate() [inlined] operator() at memory:2338:5 [opt]
    frame #5: 0x00000001024a375a deno`::Terminate() [inlined] reset at memory:2651 [opt]
    frame #6: 0x00000001024a3755 deno`::Terminate() [inlined] ~unique_ptr at memory:2605 [opt]
    frame #7: 0x00000001024a3755 deno`::Terminate() [inlined] ~unique_ptr at memory:2605 [opt]
    frame #8: 0x00000001024a3755 deno`::Terminate() [inlined] destroy at memory:1880 [opt]
    frame #9: 0x00000001024a3755 deno`::Terminate() [inlined] __destroy<std::__1::unique_ptr<v8::platform::DefaultWorkerThreadsTaskRunner::WorkerThread, std::__1::default_delete<v8::platform::DefaultWorkerThreadsTaskRunner::WorkerThread> > > at memory:1742 [opt]
    frame #10: 0x00000001024a3755 deno`::Terminate() [inlined] destroy<std::__1::unique_ptr<v8::platform::DefaultWorkerThreadsTaskRunner::WorkerThread, std::__1::default_delete<v8::platform::DefaultWorkerThreadsTaskRunner::WorkerThread> > > at memory:1595 [opt]
    frame #11: 0x00000001024a3755 deno`::Terminate() [inlined] __destruct_at_end at vector:426 [opt]
    frame #12: 0x00000001024a372f deno`::Terminate() [inlined] clear at vector:369 [opt]
    frame #13: 0x00000001024a3728 deno`::Terminate() [inlined] clear at vector:772 [opt]
    frame #14: 0x00000001024a3728 deno`::Terminate() at default-worker-threads-task-runner.cc:40 [opt]
    frame #15: 0x00000001024a2195 deno`::~DefaultPlatform() at default-platform.cc:86:65 [opt]
    frame #16: 0x00000001024a231e deno`::~DefaultPlatform() [inlined] ~DefaultPlatform at default-platform.cc:84:37 [opt]
    frame #17: 0x00000001024a2319 deno`::~DefaultPlatform() at default-platform.cc:84 [opt]
    frame #18: 0x00007fff674373cf libsystem_c.dylib`__cxa_finalize_ranges + 319
    frame #19: 0x00007fff674376b3 libsystem_c.dylib`exit + 55
    frame #20: 0x0000000101167499 deno`std::sys::unix::os::exit::hd37df0a26b830125 at os.rs:554:13 [opt]
    frame #21: 0x000000010115f9e4 deno`std::process::exit::hf7c9d77d2062e93b at process.rs:1514:4 [opt]
    frame #22: 0x00000001002dd503 deno`deno_cli::deno_error::print_err_and_exit::hd6edb51694724a0d(err=ErrBox(Box<deno::any_error::AnyError>
...

Looks like this is from destruction of static std::unique_ptr<v8::Platform> platform;. I wonder if this is a V8 issue...

@dyedgreen
Copy link
Contributor Author

dyedgreen commented Dec 19, 2019

@ry regarding #3521, I did some further investigation and found the following:

From the error message:

error: Uncaught CompileError: WebAssembly.compile(): expected 7299055 bytes, fell off end @+13        │
► $deno$/compiler.ts:710:40                                                                           │
    at window_ts_10.window.onmessage ($deno$/compiler.ts:710:40)                                      │
    at workerMain ($deno$/workers.ts:93:51)

The error says the WASM compiler expected 7299055 bytes. But downloading the sqlite.wasm file and checking (await Deno.readFile("sqlite.wasm")).length (after downloading the WASM) the WASM file is actually 612412 bytes (or 11x smaller).

This error seems to only occur when downloading the WASM via http in an import statement. So it's probably somewhat different from the issue at exit.

@dyedgreen
Copy link
Contributor Author

regarding the previous comment see #3528 😅

@dyedgreen
Copy link
Contributor Author

Is this still an issue? It seems like this problem is fixed in the latest release (0.29), but wanted to double check before closing the issue.

@hayd
Copy link
Contributor

hayd commented Jan 13, 2020

Should we add a test to avoid regression?

@bartlomieju
Copy link
Member

WASM imports were removed before 1.0, so I'm going to close this issue as no longer relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working correctly
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants