emscripten icon indicating copy to clipboard operation
emscripten copied to clipboard

Generated Wasm module fails with "stack overflow" / "memory access out of bounds" (nodejs runtime error)

Open mkarup opened this issue 1 year ago • 1 comments

I have some C code generated through the CertiCoq project. Emscripten produces a Wasm module that fails with a stack overflow/ memory access out of bounds runtime error when trying to run the module via the generated js scaffolding and nodejs (v.20.12.2).

The x86-64 binary runs without issues.

I have attached a zip containing the C files needed for running the emcc command: sm_gauss_nat.zip

Error message for command node --stack-size=1000000 sm_gauss_nat-opt_O0.js:

Stack overflow detected.  You can try increasing -sSTACK_SIZE (currently set to 100000)
/home/martin/Documents/sm_gauss_nat/sm_gauss_nat-opt_O0.js:132
      throw ex;
      ^

RuntimeError: memory access out of bounds
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6659)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6bfb)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)
    at sm_gauss_nat-opt_O0.wasm.s_compile_uncurried_uncurried_known_119 (wasm://wasm/sm_gauss_nat-opt_O0.wasm-000c23d6:wasm-function[34]:0x6d3a)

Node.js v20.12.2

Adding optimization flags doesn't seem to help, and increasing the stack size seems to cause a segmentation fault for me when trying to run with node.

Emscripten Version

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.58 (a41843e0860e52c948c1fce20307933c6631c800)
clang version 19.0.0git (https:/github.com/llvm/llvm-project 0a8cd1ed1f4f35905df318015b0dbcb69d81d7c2)
Target: wasm32-unknown-emscripten
Thread model: posix

Full command:

emcc -v -O0 -o sm_gauss_nat-opt_O0.js -w -Wno-everything -I./ sm_gauss_nat_main_wasm.c gc_stack.c CertiCoq.Benchmarks.tests.sm_gauss_nat.c glue_sm_gauss_nat.c -sALLOW_MEMORY_GROWTH=1 -sSTACK_SIZE=100000 --profiling

Output:

 /home/martin/code/emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/home/martin/code/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -Werror=implicit-function-declaration -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -v -O0 -w -Wno-everything -I./ sm_gauss_nat_main_wasm.c -c -o /tmp/emscripten_temp_ald21kk8/sm_gauss_nat_main_wasm_0.o
clang version 19.0.0git (https:/github.com/llvm/llvm-project 0a8cd1ed1f4f35905df318015b0dbcb69d81d7c2)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/martin/code/emsdk/upstream/bin
 (in-process)
 "/home/martin/code/emsdk/upstream/bin/clang-19" -cc1 -triple wasm32-unknown-emscripten -emit-obj -mrelax-all -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name sm_gauss_nat_main_wasm.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/martin/Documents/sm_gauss_nat -v -fcoverage-compilation-dir=/home/martin/Documents/sm_gauss_nat -resource-dir /home/martin/code/emsdk/upstream/lib/clang/19 -D EMSCRIPTEN -I ./ -isysroot /home/martin/code/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /home/martin/code/emsdk/upstream/lib/clang/19/include -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include -O0 -Werror=implicit-function-declaration -Wno-everything -w -ferror-limit 19 -fvisibility=default -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fcolor-diagnostics -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_ald21kk8/sm_gauss_nat_main_wasm_0.o -x c sm_gauss_nat_main_wasm.c
clang -cc1 version 19.0.0git based upon LLVM 19.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 .
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/compat
 /home/martin/code/emsdk/upstream/lib/clang/19/include
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /home/martin/code/emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/home/martin/code/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -Werror=implicit-function-declaration -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -v -O0 -w -Wno-everything -I./ gc_stack.c -c -o /tmp/emscripten_temp_ald21kk8/gc_stack_1.o
clang version 19.0.0git (https:/github.com/llvm/llvm-project 0a8cd1ed1f4f35905df318015b0dbcb69d81d7c2)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/martin/code/emsdk/upstream/bin
 (in-process)
 "/home/martin/code/emsdk/upstream/bin/clang-19" -cc1 -triple wasm32-unknown-emscripten -emit-obj -mrelax-all -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name gc_stack.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/martin/Documents/sm_gauss_nat -v -fcoverage-compilation-dir=/home/martin/Documents/sm_gauss_nat -resource-dir /home/martin/code/emsdk/upstream/lib/clang/19 -D EMSCRIPTEN -I ./ -isysroot /home/martin/code/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /home/martin/code/emsdk/upstream/lib/clang/19/include -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include -O0 -Werror=implicit-function-declaration -Wno-everything -w -ferror-limit 19 -fvisibility=default -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fcolor-diagnostics -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_ald21kk8/gc_stack_1.o -x c gc_stack.c
clang -cc1 version 19.0.0git based upon LLVM 19.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 .
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/compat
 /home/martin/code/emsdk/upstream/lib/clang/19/include
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /home/martin/code/emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/home/martin/code/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -Werror=implicit-function-declaration -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -v -O0 -w -Wno-everything -I./ CertiCoq.Benchmarks.tests.sm_gauss_nat.c -c -o /tmp/emscripten_temp_ald21kk8/CertiCoq.Benchmarks.tests.sm_gauss_nat_2.o
clang version 19.0.0git (https:/github.com/llvm/llvm-project 0a8cd1ed1f4f35905df318015b0dbcb69d81d7c2)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/martin/code/emsdk/upstream/bin
 (in-process)
 "/home/martin/code/emsdk/upstream/bin/clang-19" -cc1 -triple wasm32-unknown-emscripten -emit-obj -mrelax-all -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name CertiCoq.Benchmarks.tests.sm_gauss_nat.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/martin/Documents/sm_gauss_nat -v -fcoverage-compilation-dir=/home/martin/Documents/sm_gauss_nat -resource-dir /home/martin/code/emsdk/upstream/lib/clang/19 -D EMSCRIPTEN -I ./ -isysroot /home/martin/code/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /home/martin/code/emsdk/upstream/lib/clang/19/include -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include -O0 -Werror=implicit-function-declaration -Wno-everything -w -ferror-limit 19 -fvisibility=default -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fcolor-diagnostics -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_ald21kk8/CertiCoq.Benchmarks.tests.sm_gauss_nat_2.o -x c CertiCoq.Benchmarks.tests.sm_gauss_nat.c
clang -cc1 version 19.0.0git based upon LLVM 19.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 .
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/compat
 /home/martin/code/emsdk/upstream/lib/clang/19/include
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /home/martin/code/emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/home/martin/code/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -Werror=implicit-function-declaration -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -v -O0 -w -Wno-everything -I./ glue_sm_gauss_nat.c -c -o /tmp/emscripten_temp_ald21kk8/glue_sm_gauss_nat_3.o
clang version 19.0.0git (https:/github.com/llvm/llvm-project 0a8cd1ed1f4f35905df318015b0dbcb69d81d7c2)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/martin/code/emsdk/upstream/bin
 (in-process)
 "/home/martin/code/emsdk/upstream/bin/clang-19" -cc1 -triple wasm32-unknown-emscripten -emit-obj -mrelax-all -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name glue_sm_gauss_nat.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/martin/Documents/sm_gauss_nat -v -fcoverage-compilation-dir=/home/martin/Documents/sm_gauss_nat -resource-dir /home/martin/code/emsdk/upstream/lib/clang/19 -D EMSCRIPTEN -I ./ -isysroot /home/martin/code/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /home/martin/code/emsdk/upstream/lib/clang/19/include -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include -O0 -Werror=implicit-function-declaration -Wno-everything -w -ferror-limit 19 -fvisibility=default -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fcolor-diagnostics -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp_ald21kk8/glue_sm_gauss_nat_3.o -x c glue_sm_gauss_nat.c
clang -cc1 version 19.0.0git based upon LLVM 19.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 .
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include/compat
 /home/martin/code/emsdk/upstream/lib/clang/19/include
 /home/martin/code/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /home/martin/code/emsdk/upstream/bin/clang --version
cache:INFO: generating system asset: symbol_lists/ddda1e3705a2cc29dceb5e6eb4f1cd9a3a4e8663.json... (this will be cached in "/home/martin/code/emsdk/upstream/emscripten/cache/symbol_lists/ddda1e3705a2cc29dceb5e6eb4f1cd9a3a4e8663.json" for subsequent builds)
 /home/martin/code/emsdk/node/16.20.0_64bit/bin/node /home/martin/code/emsdk/upstream/emscripten/src/compiler.mjs /tmp/tmpsoi5da8f.json --symbols-only
cache:INFO:  - ok
 /home/martin/code/emsdk/upstream/bin/wasm-ld -o sm_gauss_nat-opt_O0.wasm -L/home/martin/code/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten /tmp/emscripten_temp_ald21kk8/sm_gauss_nat_main_wasm_0.o /tmp/emscripten_temp_ald21kk8/gc_stack_1.o /tmp/emscripten_temp_ald21kk8/CertiCoq.Benchmarks.tests.sm_gauss_nat_2.o /tmp/emscripten_temp_ald21kk8/glue_sm_gauss_nat_3.o -lGL-getprocaddr -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmpiyvbk_s_libemscripten_js_symbols.so --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=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export=_emscripten_stack_restore --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=100000 --max-memory=2147483648 --initial-heap=16777216 --no-entry --stack-first --table-base=1
 /home/martin/code/emsdk/upstream/bin/llvm-objcopy sm_gauss_nat-opt_O0.wasm sm_gauss_nat-opt_O0.wasm --remove-section=.debug* --remove-section=producers
 /home/martin/code/emsdk/upstream/bin/wasm-emscripten-finalize -g --dyncalls-i64 --pass-arg=legalize-js-interface-exported-helpers sm_gauss_nat-opt_O0.wasm -o sm_gauss_nat-opt_O0.wasm --detect-features
 /home/martin/code/emsdk/node/16.20.0_64bit/bin/node /home/martin/code/emsdk/upstream/emscripten/src/compiler.mjs /tmp/tmprp74a2fd.json

mkarup avatar Apr 29 '24 10:04 mkarup

increasing the stack size seems to cause a segmentation fault for me when trying to run with node.

That should fix it, so that segfault needs to be looked into. Do you mean a segfault in node itself, or in the compiled code? What is the output you see?

kripken avatar Apr 29 '24 20:04 kripken

Sorry for the late, late reply. Adding -O1 and specifying a large enough stack size and initial memory produces the correct result, so that's a mistake on my part.

As far as I can tell, the segfault arises from specifying a stack size that is too large when invoking node itself with --stack-size=X, e.g. with X=11000000 on my machine, but maybe that is intended/ the expected behavior with such a large size? (but this is something with node, not emscripten)

With no optimization flags, I can also increase the stack size and initial memory to the point where I don't get the stack overflow/ memory out of bounds errors, but the behavior differs, similar to this issue, so I will continue in that other issue. For what it's worth, I tried compiling with both the undefined behavior sanitizer and the address sanitizer, but the binary that is produced with sanitizers has functions with too many locals (I also tried with the minimal runtime), and adding -sASSERTIONS=2 and -sSAFE_HEAP doesn't tell me anything.

mkarup avatar May 16 '24 19:05 mkarup