wasm-pack: Segmentation fault after small patch
š Bug description
Iām getting a segfault when I run wasm-pack with no arguments. Iāve made some small non-unsafe changes to the codebase.
Sometimes, instead of a segfault, I get a failed assertion in curl-sys:
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
left: `2`,
right: `0`', **/home/.cargo/registry/src/github.com-1ecc6299db9ec823/curl-0.4.20/src/lib.rs:92:13**
which is here: curl assert fail.
Here is the stack trace from the segfault core dump
May 19 15:44:30 systemd-coredump[11016]: Process 11013 (wasm-pack) of user 1000 dumped core.
Stack trace of thread 11014:
#0 0x00007fb5df46836d __pthread_rwlock_unlock (libpthread.so.0)
#1 0x00007fb5df17e3ba CRYPTO_THREAD_unlock (libcrypto.so.1.1)
#2 0x00007fb5df0f1e07 n/a (libcrypto.so.1.1)
#3 0x00007fb5df0f21c8 ERR_load_strings_const (libcrypto.so.1.1)
#4 0x00007fb5df679aea ERR_load_SSL_strings (libssl.so.1.1)
#5 0x00007fb5df679b1a n/a (libssl.so.1.1)
#6 0x00007fb5df46a5cf __pthread_once_slow (libpthread.so.0)
#7 0x00007fb5df17e40a CRYPTO_THREAD_run_once (libcrypto.so.1.1)
#8 0x00007fb5df679f24 OPENSSL_init_ssl (libssl.so.1.1)
#9 0x0000560063ae2fff n/a (/home/devel/non-work/wasm-pack/target/debug/wasm-pack
š Steps to reproduce
- Clone the repo above
- run
wasm-pack(e.g.cargo run)
š Your environment
wasm-pack version: latest git rustc version: 1.34.2
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 26 (7 by maintainers)
Iām seeing whatās probably the same segfault. It looks like a race condition within openssl triggered by exiting (running atexit handlers) while the thread spawned by
background_check_for_updatesis initializing openssl.Even if openssl handled shutdown mid-initialization, I suspect youād still be in trouble if the version check thread gets as far as actually using openssl while the main thread exits the process. Itād be nice if wasm-pack could wait for that other thread before exiting, but unless it can interrupt the check in flight Iām guessing thatād be a bit slow⦠Havenāt investigated what it would take to interrupt the check and exit cleanly.
Iām also seeing this with a locally built wasm-pack (from revision 30a95a42f14abb5b7d6e50f98256da7400046199, built with Rust 1.35.0, with a local change that shouldnāt matter if we exit this early). I havenāt investigated if official builds of wasm-pack are less crashy (or why that might be).
#653 (and any other changes that rate-limit the version check) might mostly hide this issue.
The exact stack of the crashing thread varies, but usually looks like:
Thereās another thread that looks like:
or:
Looking at openssl (Iām using 1.1.0k), it uses pthread_once (or equivalent) to run its initialization function once, and registers an atexit handler that tears everything down quite early in that initialization. Weāre crashing trying to use a static lock in o_names.c that got nulled out by
OBJ_NAME_cleanup, called fromevp_cleanup_int, called byOPENSSL_cleanup, which is registered as an atexit handler byossl_init_base, which runs early inOPENSSL_init_crypto. which gets called byOPENSSL_init_sslbefore the call toossl_init_ssl_basethe crashing thread is in.The backtraces from @derekdreery also contain openssl initialization functions and also occur when exiting immediately, so I think itās the same crash.
The curl-sys assert was curl failing to initialize. I havenāt confirmed it has a similar race (and handles it better by failing initialization instead of crashing) but it seems plausible.
The segfault only happens when vendored OpenSSL is enabled, though, so running
cargo install --path . --no-default-featureswill get you a working version ofwasm-pack.I was able to boil the segfault down to this minimal repro:
This is the backtrace:
Iām still not really sure why itās happening, though, and particularly why including the bit of code referencing
reqwestthatās never reached is necessary. The segfault happens to also come fromlibcrypto, but it doesnāt seem particularly related to the original issue.If youāre segfaulting only on specific
wasm-packinvocations, youāre probably hitting a different bug. This bug covers a race condition that can be hit by runningwasm-packwith no arguments (or other wasm-pack invocations that are fast). If youāre only segfaulting when building something, itās probably a different bug.Please share a backtrace for the segfault (and if it doesnāt look like this bug, probably best to file a new one and CC me if you want me to look at the backtraces).
I had a quick look to see if thereās an obvious difference between LibreSSL and OpenSSL, or if itās just more timing changes hiding the problem. There is a real difference, but I donāt know if itās intentional or not.
Comparing OpenSSL 1.1.1d and LibreSSL 3.0.2, the important difference is that I see no atexit() handlers in LibreSSL.
However, that might be because LibreSSL currently does not need them, rather than by design. The lock whose cleanup triggered the segfault I saw before is also not present in libressl. It looks like this lock was introduced in openssl relatively recently (https://github.com/openssl/openssl/pull/3525), and (assuming https://github.com/libressl-portable/openbsd/commits/master/src/lib/libcrypto/objects/o_names.c is current) libressl has not yet picked up those changes.
So itās possible libressl still has that race condition, and that if they choose to fix it the same way openssl did itāll start crashing wasm-pack the same way. (Or if they start using atexit() for cleanup for other reasons.) Unless someone confirms libressl intentionally does not use atexit handlers I wouldnāt recommend LibreSSL as the fix for this one.
I would love to see this documented somewhere, but maybe itās a bit too early to say LibreSSL fixes the segfaults before others could confirm the same?
Thanks for the great work on wasm-pack, by the way! ā¤ļø
Iām happy to report that with LibreSSL 3.0.2, the race conditions I experienced are gone in both release and debug modes.