Skip to content

Runtime crash when calling poll() from a worker thread with pthreads and Asyncify #27291

Description

@Young-Lord

Summary

Calling poll() from a pthread worker thread crashes at runtime when the program is built with -pthread and -sASYNCIFY.

Version of emscripten/emsdk

$ emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 6.0.3-git (22383d7400b93ea4404b72d6cbe0bff837b8dc22)
clang version 23.0.0git (https:/github.com/llvm/llvm-project 4708581453ead90685a55e343cc5ace1e1ddabb1)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /root/emsdk/upstream/bin
Build config: +assertions

Node.js used to run the built output: v26.2.0

Repro source

#include <poll.h>
#include <pthread.h>
#include <stdio.h>

static void *poll_thread(void *arg) {
  (void)arg;
  puts("[c] poll start");
  int rc = poll(NULL, 0, 1);
  printf("[c] poll rc=%d\n", rc);
  return NULL;
}

int main(void) {
  pthread_t t;
  pthread_create(&t, NULL, poll_thread, NULL);
  pthread_join(t, NULL);
  puts("[c] done");
  return 0;
}

Expected behavior

[c] poll start
[c] poll rc=0
[c] done

Case 1: default build

Failing command line in full

Link succeeds. Runtime fails with:

node dist/default.js

Output (exit code 1):

[c] poll start
Aborted(import _emscripten_receive_on_main_thread_js was not in ASYNCIFY_IMPORTS, but changed the state)
RuntimeError: Aborted(import _emscripten_receive_on_main_thread_js was not in ASYNCIFY_IMPORTS, but changed the state)
    at abort (.../dist/default.js:1:15046)
    at imports.<computed> (.../dist/default.js:1:86822)
    at wasm://wasm/00036c6e:wasm-function[67]:0x5174
    at wasm://wasm/00036c6e:wasm-function[60]:0x47fe
    at wasm://wasm/00036c6e:wasm-function[29]:0x1c6e
    at wasm://wasm/00036c6e:wasm-function[70]:0x53c2
    at wasm://wasm/00036c6e:wasm-function[71]:0x5679
    at wasm://wasm/00036c6e:wasm-function[38]:0x2410
    at wasm://wasm/00036c6e:wasm-function[23]:0x12b9
    at __asyncify_wrapper_23 (.../dist/default.js:1:87004)

(Abort also prints the minified default.js source line between the Aborted(...) message and the RuntimeError; omitted here.)

Without -sASSERTIONS=2, the same build exits with code 1 but does not print the ASYNCIFY_IMPORTS abort message.

Full link command and output with -v appended

emcc main.c \
  -O2 \
  -pthread -sUSE_PTHREADS=1 \
  -sASYNCIFY \
  -sASSERTIONS=2 \
  -sENVIRONMENT=node,web,worker \
  -sEXIT_RUNTIME=1 \
  -o dist/default.js \
  -v
 /root/emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/root/emsdk/upstream/emscripten/cache/sysroot -D__EMSCRIPTEN_SHARED_MEMORY__=1 -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -O2 -pthread -v -c main.c -o /tmp/emscripten_temp_urode733/main.o
clang version 23.0.0git (https:/github.com/llvm/llvm-project 4708581453ead90685a55e343cc5ace1e1ddabb1)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /root/emsdk/upstream/bin
Build config: +assertions
 (in-process)
 "/root/emsdk/upstream/bin/clang-23" -cc1 -triple wasm32-unknown-emscripten -O2 -emit-obj -disable-free -clear-ast-before-backend -main-file-name main.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-feature +atomics -target-feature +bulk-memory -target-feature +mutable-globals -target-feature +sign-ext -target-cpu generic -fvisibility=hidden -debugger-tuning=gdb -fdebug-compilation-dir=/root/emscripten-bug-poll -v -fcoverage-compilation-dir=/root/emscripten-bug-poll -resource-dir /root/emsdk/upstream/lib/clang/23 -D __EMSCRIPTEN_SHARED_MEMORY__=1 -isysroot /root/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /root/emsdk/upstream/lib/clang/23/include -internal-isystem /root/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /root/emsdk/upstream/emscripten/cache/sysroot/include -ferror-limit 19 -pthread -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fno-color-diagnostics -vectorize-loops -vectorize-slp -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_urode733/main.o -x c main.c
clang -cc1 version 23.0.0git based upon LLVM 23.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/root/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 /root/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /root/emsdk/upstream/emscripten/cache/sysroot/include/compat
 /root/emsdk/upstream/lib/clang/23/include
 /root/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /root/emsdk/upstream/bin/clang --version
emcc: warning: USE_PTHREADS is deprecated (prefer the standard -pthread flag). Please open a bug if you have a continuing need for this setting [-Wdeprecated]
 /root/emsdk/upstream/bin/wasm-ld -o dist/default.wasm /tmp/tmpnlv4s8vslibemscripten_js_symbols.so -Bstatic --import-memory --shared-memory --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=_emscripten_stack_alloc --export=_emscripten_thread_free_data --export=_emscripten_thread_crashed --export=__funcs_on_exit --export=__wasm_call_ctors --export=_emscripten_tls_init --export=_emscripten_thread_init --export=pthread_self --export=__set_thread_state --export=_emscripten_stack_restore --export=emscripten_stack_set_limits --export=_emscripten_thread_exit --export=malloc --export=free --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-if-defined=fflush --export-table -z stack-size=65536 --no-growable-memory --initial-memory=16777216 --no-entry --no-stack-first --table-base=1 --global-base=1024 /tmp/emscripten_temp_urode733/main.o -L/root/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten -L/root/emsdk/upstream/emscripten/src/lib /root/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/crtbegin-mt.o -lGL-mt-getprocaddr -lal -lhtml5 -lstubs-debug -lc-mt-debug -ldlmalloc-mt-debug -lclang_rt.builtins-mt -lc++-debug-mt-noexcept -lc++abi-debug-mt-noexcept -lsockets-mt -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr
 /root/emsdk/upstream/bin/llvm-objcopy dist/default.wasm dist/default.wasm '--remove-section=llvm.func_attr.annotate.*' --remove-section=producers '--remove-section=.debug*'
 /root/emsdk/upstream/bin/wasm-emscripten-finalize --bigint --no-legalize-javascript-ffi --check-stack-overflow dist/default.wasm -o dist/default.wasm --detect-features
 /root/emsdk/upstream/bin/wasm-opt --strip-target-features --post-emscripten -O2 --low-memory-unused --asyncify --pass-arg=asyncify-asserts --pass-arg=asyncify-propagate-addlist '--pass-arg=asyncify-imports@env.invoke_*,env.__asyncjs__*,*.fd_sync,*.emscripten_promise_await,*.emscripten_promise_await_unchecked,*.__syscall_poll,*.emscripten_idb_load,*.emscripten_idb_store,*.emscripten_idb_delete,*.emscripten_idb_exists,*.emscripten_idb_clear,*.emscripten_sleep,*.emscripten_wget_data,*.emscripten_scan_registers,*.emscripten_fiber_swap' --zero-filled-memory --pass-arg=directize-initial-contents-immutable dist/default.wasm -o dist/default.wasm --mvp-features --enable-threads --enable-bulk-memory --enable-bulk-memory-opt --enable-call-indirect-overlong --enable-multivalue --enable-mutable-globals --enable-nontrapping-float-to-int --enable-reference-types --enable-sign-ext
 /root/emsdk/node/22.16.0_64bit/bin/node /root/emsdk/upstream/emscripten/tools/acorn-optimizer.mjs /tmp/emscripten_temp_urode733/default.js JSDCE --minify-whitespace -o /tmp/emscripten_temp_urode733/default.jso1.js

Case 2: with -sASYNCIFY_IMPORTS

Failing command line in full

Link succeeds. Runtime fails with:

node dist/importlisted.js

Output (exit code 1):

[c] poll start
TypeError: rtn.then is not a function
    at __emscripten_receive_on_main_thread_js (.../dist/importlisted.js:1:80325)
    at imports.<computed> (.../dist/importlisted.js:1:86583)
    at wasm://wasm/000371fa:wasm-function[67]:0x527e
    at wasm://wasm/000371fa:wasm-function[60]:0x47fe
    at wasm://wasm/000371fa:wasm-function[29]:0x1c6e
    at wasm://wasm/000371fa:wasm-function[70]:0x5525
    at wasm://wasm/000371fa:wasm-function[71]:0x57dc
    at wasm://wasm/000371fa:wasm-function[38]:0x2410
    at wasm://wasm/000371fa:wasm-function[23]:0x12b9
    at __asyncify_wrapper_23 (.../dist/importlisted.js:1:87047)

(Abort also prints the minified importlisted.js source line before the TypeError; omitted here.)

This happens at both -O0 and -O2 when the import is listed.

Full link command and output with -v appended

emcc main.c \
  -O2 \
  -pthread -sUSE_PTHREADS=1 \
  -sASYNCIFY \
  -sASSERTIONS=2 \
  -sENVIRONMENT=node,web,worker \
  -sEXIT_RUNTIME=1 \
  -sASYNCIFY_IMPORTS="['_emscripten_receive_on_main_thread_js']" \
  -o dist/importlisted.js \
  -v
 /root/emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/root/emsdk/upstream/emscripten/cache/sysroot -D__EMSCRIPTEN_SHARED_MEMORY__=1 -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -O2 -pthread -v -c main.c -o /tmp/emscripten_temp_6pouatn5/main.o
clang version 23.0.0git (https:/github.com/llvm/llvm-project 4708581453ead90685a55e343cc5ace1e1ddabb1)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /root/emsdk/upstream/bin
Build config: +assertions
 (in-process)
 "/root/emsdk/upstream/bin/clang-23" -cc1 -triple wasm32-unknown-emscripten -O2 -emit-obj -disable-free -clear-ast-before-backend -main-file-name main.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-feature +atomics -target-feature +bulk-memory -target-feature +mutable-globals -target-feature +sign-ext -target-cpu generic -fvisibility=hidden -debugger-tuning=gdb -fdebug-compilation-dir=/root/emscripten-bug-poll -v -fcoverage-compilation-dir=/root/emscripten-bug-poll -resource-dir /root/emsdk/upstream/lib/clang/23 -D __EMSCRIPTEN_SHARED_MEMORY__=1 -isysroot /root/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /root/emsdk/upstream/lib/clang/23/include -internal-isystem /root/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /root/emsdk/upstream/emscripten/cache/sysroot/include -ferror-limit 19 -pthread -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fno-color-diagnostics -vectorize-loops -vectorize-slp -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_6pouatn5/main.o -x c main.c
clang -cc1 version 23.0.0git based upon LLVM 23.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/root/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 /root/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /root/emsdk/upstream/emscripten/cache/sysroot/include/compat
 /root/emsdk/upstream/lib/clang/23/include
 /root/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /root/emsdk/upstream/bin/clang --version
emcc: warning: USE_PTHREADS is deprecated (prefer the standard -pthread flag). Please open a bug if you have a continuing need for this setting [-Wdeprecated]
 /root/emsdk/upstream/bin/wasm-ld -o dist/importlisted.wasm /tmp/tmprrk9ogzwlibemscripten_js_symbols.so -Bstatic --import-memory --shared-memory --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=_emscripten_stack_alloc --export=_emscripten_thread_free_data --export=_emscripten_thread_crashed --export=__funcs_on_exit --export=__wasm_call_ctors --export=_emscripten_tls_init --export=_emscripten_thread_init --export=pthread_self --export=__set_thread_state --export=_emscripten_stack_restore --export=emscripten_stack_set_limits --export=_emscripten_thread_exit --export=malloc --export=free --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-if-defined=fflush --export-table -z stack-size=65536 --no-growable-memory --initial-memory=16777216 --no-entry --no-stack-first --table-base=1 --global-base=1024 /tmp/emscripten_temp_6pouatn5/main.o -L/root/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten -L/root/emsdk/upstream/emscripten/src/lib /root/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/crtbegin-mt.o -lGL-mt-getprocaddr -lal -lhtml5 -lstubs-debug -lc-mt-debug -ldlmalloc-mt-debug -lclang_rt.builtins-mt -lc++-debug-mt-noexcept -lc++abi-debug-mt-noexcept -lsockets-mt -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr
 /root/emsdk/upstream/bin/llvm-objcopy dist/importlisted.wasm dist/importlisted.wasm '--remove-section=llvm.func_attr.annotate.*' --remove-section=producers '--remove-section=.debug*'
 /root/emsdk/upstream/bin/wasm-emscripten-finalize --bigint --no-legalize-javascript-ffi --check-stack-overflow dist/importlisted.wasm -o dist/importlisted.wasm --detect-features
 /root/emsdk/upstream/bin/wasm-opt --strip-target-features --post-emscripten -O2 --low-memory-unused --asyncify --pass-arg=asyncify-asserts --pass-arg=asyncify-propagate-addlist '--pass-arg=asyncify-imports@env._emscripten_receive_on_main_thread_js,env.invoke_*,env.__asyncjs__*,*.fd_sync,*.emscripten_promise_await,*.emscripten_promise_await_unchecked,*.__syscall_poll,*.emscripten_idb_load,*.emscripten_idb_store,*.emscripten_idb_delete,*.emscripten_idb_exists,*.emscripten_idb_clear,*.emscripten_sleep,*.emscripten_wget_data,*.emscripten_scan_registers,*.emscripten_fiber_swap' --zero-filled-memory --pass-arg=directize-initial-contents-immutable dist/importlisted.wasm -o dist/importlisted.wasm --mvp-features --enable-threads --enable-bulk-memory --enable-bulk-memory-opt --enable-call-indirect-overlong --enable-multivalue --enable-mutable-globals --enable-nontrapping-float-to-int --enable-reference-types --enable-sign-ext
 /root/emsdk/node/22.16.0_64bit/bin/node /root/emsdk/upstream/emscripten/tools/acorn-optimizer.mjs /tmp/emscripten_temp_6pouatn5/importlisted.js JSDCE --minify-whitespace -o /tmp/emscripten_temp_6pouatn5/importlisted.jso1.js

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions