emscripten-core / emscripten-core/emscripten
Embind + asyncify throws BindingError with ASan enabled
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
Description
**Version of emscripten/emsdk:**
```
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.16 (6f1214164cb4b854755689060e91fd8167bc97a4)
clang version 15.0.0 (https://github.com/llvm/llvm-project ffa7384f10b89b6322c827d29d25108e34b8f6f0)
Target: wasm32-unknown-emscripten
Thread model: posix
```
**Full link command and output with `-v` appended:**
```
/home/dragon/code/c/emsdk/upstream/emscripten/em++ -Wall -pthread -std=c++14 -Wall -pthread -pthread -Wall -funroll-loops -Wno-ignored-attributes -Wno-unused-result -march=native -maes -mrdseed -std=c++11 -O3 -Wall -pthread -pthread -Wall -funroll-loops -Wno-ignored-attributes -Wno-unused-result -march=native -maes -mrdseed -pthread -Wall -funroll-loops -Wno-ignored-attributes -Wno-unused-result -march=native -maes -mrdseed -std=c++11 -O3 -O3 -DNDEBUG -fsanitize=address -O3 -g -sASYNCIFY -sWASM_BIGINT -sMODULARIZE -sEXPORT_NAME=\"createLarchClient\" -sPTHREAD_POOL_SIZE=5 -sEXPORTED_RUNTIME_METHODS=[\"FS\"] -sALLOW_MEMORY_GROWTH -v --bind @CMakeFiles/client_lib.dir/objects1.rsp -o ../../build/bin/client_lib.js @CMakeFiles/client_lib.dir/linklibs.rsp
em++: warning: USE_PTHREADS + ALLOW_MEMORY_GROWTH may run non-wasm code slowly, see https://github.com/WebAssembly/design/issues/1271 [-Wpthreads-mem-growth]
"/home/dragon/code/c/emsdk/upstream/bin/wasm-ld" -o ../../build/bin/client_lib.wasm CMakeFiles/client_lib.dir/client_lib.cc.o ../src/libClient.a ../../zkboo/src/libProver.a ../../zkboo/libBase.a /home/dragon/code/crypto/prefix/lib/libssl.a /home/dragon/code/crypto/prefix/lib/libcrypto.a -L/home/dragon/code/c/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten /home/dragon/code/c/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/crtbegin.o --whole-archive -lembind-rtti --no-whole-archive -lGL-mt -lal -lhtml5 -lstubs -lc-mt-asan -ldlmalloc-mt -lcompiler_rt-mt -lc++-mt-noexcept -lc++abi-mt-noexcept --whole-archive -lasan_rt-mt --no-whole-archive -lasan_js -lubsan_rt-mt -llsan_common_rt-mt -lsanitizer_common_rt-mt -lsockets-mt -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --import-undefined --import-memory --shared-memory --export-if-defined=main --export-if-defined=_emscripten_thread_init --export-if-defined=_emscripten_thread_exit --export-if-defined=_emscripten_thread_crashed --export-if-defined=_emscripten_tls_init --export-if-defined=pthread_self --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__main_argc_argv --export=emscripten_stack_get_base --export=emscripten_stack_get_end --export=emscripten_stack_set_limits --export=stackSave --export=stackRestore --export=stackAlloc --export=__wasm_call_ctors --export=__errno_location --export=emscripten_dispatch_to_thread_ --export=_emscripten_thread_free_data --export=emscripten_main_browser_thread_id --export=emscripten_main_thread_process_queued_calls --export=emscripten_run_in_main_runtime_thread_js --export=memalign --export=emscripten_builtin_memalign --export=emscripten_builtin_malloc --export=emscripten_builtin_free --export=asan_c_load_1 --export=asan_c_load_1u --export=asan_c_load_2 --export=asan_c_load_2u --export=asan_c_load_4 --export=asan_c_load_4u --export=asan_c_load_f --export=asan_c_load_d --export=asan_c_store_1 --export=asan_c_store_1u --export=asan_c_store_2 --export=asan_c_store_2u --export=asan_c_store_4 --export=asan_c_store_4u --export=asan_c_store_f --export=asan_c_store_d --export=__funcs_on_exit --export=malloc --export=free --export=__cxa_is_pointer_type --export=ntohs --export=htons --export-table -z stack-size=5242880 --initial-memory=323616768 --no-entry --max-memory=2147483648 --global-base=306790400
"/home/dragon/code/c/emsdk/upstream/bin/wasm-emscripten-finalize" -g --bigint --no-legalize-javascript-ffi --dwarf ../../build/bin/client_lib.wasm -o ../../build/bin/client_lib.wasm --detect-features
"/home/dragon/code/c/emsdk/node/14.18.2_64bit/bin/node" /home/dragon/code/c/emsdk/upstream/emscripten/src/compiler.js /tmp/tmpvxg8xkrl.json
em++: warning: running limited binaryen optimizations because DWARF info requested (or indirectly required) [-Wlimited-postlink-optimizations]
"/home/dragon/code/c/emsdk/upstream/bin/wasm-opt" --post-emscripten -O3 --low-memory-unused --asyncify --pass-arg=asyncify-imports@env.invoke_*,env.emscripten_sleep,env.emscripten_wget,env.emscripten_wget_data,env.emscripten_idb_load,env.emscripten_idb_store,env.emscripten_idb_delete,env.emscripten_idb_exists,env.emscripten_idb_load_blob,env.emscripten_idb_store_blob,env.SDL_Delay,env.emscripten_scan_registers,env.emscripten_lazy_load_code,env.emscripten_fiber_swap,wasi_snapshot_preview1.fd_sync,env.__wasi_fd_sync,env._emval_await,env._dlopen_js,env.__asyncjs__* --pass-arg=asyncify-removelist@asan_c_load_1,asan_c_load_1u,asan_c_load_2,asan_c_load_2u,asan_c_load_4,asan_c_load_4u,asan_c_load_f,asan_c_load_d,asan_c_store_1,asan_c_store_1u,asan_c_store_2,asan_c_store_2u,asan_c_store_4,asan_c_store_4u,asan_c_store_f,asan_c_store_d --zero-filled-memory --strip-producers ../../build/bin/client_lib.wasm -o ../../build/bin/client_lib.wasm -g --mvp-features --enable-threads --enable-bulk-memory --enable-mutable-globals --enable-sign-ext --enable-simd
"/home/dragon/code/c/emsdk/node/14.18.2_64bit/bin/node" /home/dragon/code/c/emsdk/upstream/emscripten/tools/acorn-optimizer.js /tmp/emscripten_temp_w6il97sr/client_lib.js growableHeap
"/home/dragon/code/c/emsdk/node/14.18.2_64bit/bin/node" /home/dragon/code/c/emsdk/upstream/emscripten/tools/acorn-optimizer.js /tmp/emscripten_temp_w6il97sr/client_lib.js.pgrow.js asanify
"/home/dragon/code/c/emsdk/node/14.18.2_64bit/bin/node" /home/dragon/code/c/emsdk/upstream/emscripten/tools/preprocessor.js /tmp/emscripten_temp_w6il97sr/settings.js worker.js --expandMacros
```
When building with ASan, a BindingError is thrown when calling an async JS function from C++ via embind and awaiting the promise:
```
BindingError: Cannot use deleted val. handle = 0
at BindingError. (http://localhost:3000/client_lib.js:4039:15)
at new BindingError (eval at createNamedFunction (http://localhost:3000/client_lib.js:4032:9), :4:34)
at throwBindingError (http://localhost:3000/client_lib.js:4194:8)
at Object.toValue (http://localhost:3000/client_lib.js:5413:4)
at __emval_as (http://localhost:3000/client_lib.js:5896:17)
at wasm::LogService::init(InitRequest const&) (http://localhost:3000/client_lib.wasm:wasm-function[143]:0x7f887)
at Client::Initialize() (http://localhost:3000/client_lib.wasm:wasm-function[121]:0x4a981)
at Client__Initialize(unsigned long) (http://localhost:3000/client_lib.wasm:wasm-function[228]:0xaf626)
at emscripten::internal::Invoker::invoke(int (*)(unsigned long), unsigned long) (http://localhost:3000/client_lib.wasm:wasm-function[227]:0xaf530)
at dynCall_iii (http://localhost:3000/client_lib.wasm:wasm-function[6355]:0xc83b21)
```
C++ side:
```cpp
InitResponse init(const InitRequest& req) {
val proxy = val::module_property("logServiceProxy");
val result = proxy.call("init", req).await();
return result.as();
}
```
The error occurs after the `init` function has been called on the JS side, but before the promise is resolved. It seems like the C++ side might be returning immediately instead of waiting properly. UBSan appears to work fine.
I tried to add debugging around each method call, but unfortunately nothing is printed even with `std::flush`.
```cpp
InitResponse init(const InitRequest& req) {
std::cerr << "c init start rid=" << req.id << "\n" << std::flush;
val proxy = val::module_property("logServiceProxy");
std::cerr << "c init proxy=" << proxy.as_handle() << "\n" << std::flush;
val promise = proxy.call("init", req);
std::cerr << "c init promise=" << promise.as_handle() << "\n" << std::flush;
val result = promise.await();
std::cerr << "c init result=" << result.as_handle() << "\n" << std::flush;
return result.as();
}
```
I'm not sure if this is important, but building with -O3 and without -g results in the following warnings:
```
warning: Asyncify removelist contained a non-existing function name: asan_c_load_4u (asan_c_load_4u)
warning: Asyncify removelist contained a non-existing function name: asan_c_store_1u (asan_c_store_1u)
warning: Asyncify removelist contained a non-existing function name: asan_c_store_2u (asan_c_store_2u)
warning: Asyncify removelist contained a non-existing function name: asan_c_store_4u (asan_c_store_4u)
```
The same error occurs with all combinations of -O1, -O3, and -g.
Contributor guide
Assessment
This issue has not been assessed yet.