emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.6k stars 3.28k forks source link

Problem when compiling code that has symbol collision with WASI API #22205

Open var77 opened 2 months ago

var77 commented 2 months ago

Version of emscripten/emsdk: 3.1.62

Issue Description

Hi, I am trying to compile a project into wasm that has a function with name proc_exit It seems that proc_exit is a special WASI name that is part of the WASM POSIX API. Usually emscripten generates a JS wrapper for this function and exposes it to the underlying WASM that could have been compiled from C sources, for example. Then, both js and C code can call this proc_exit to exit the process. However, I run into a runtime error when my C code contains an unrelated function with name proc_exit. It seems emscripten sees the presence of my function with the same name and decides to not create the special proc_exit function to act as js-wasm/WASI bridge.

I ran into this problem when compiling postgres, which has a function named proc_exit.

My understanding is that emscripted could expose its WASI API function, regardless of existence of homonymous functions in the source project. To avoid name collisions, emscripten could generate special attributes to expose the WASI api functions under special prefix.

Please find minimal reproducing example of the issue below to compile and run make all . I would expect to open index.html in the browser and not see any error, but I see an error:

Import #15 "wasi_snapshot_preview1" "proc_exit": function import requires a callable

Does the issue make sense? Is it a real problem or am I misunderstanding something? What are your thoughts on the proposed solution?

Code

main.c

void proc_exit(int status) { (void)status; }

Makefile

all:
    emcc main.c  -sMAIN_MODULE -s EXPORT_ALL -o index.html
    python -m http.server 8888 -d .
sbc100 commented 1 month ago

Yup, that does sounds like a reasonable request. The wasi_snapshot_preview1.proc_exit should not be confused with the a proc_exit symbol at the C level. I suspect this might be harder than it appears to solve but I'll give it a go.

sbc100 commented 1 month ago

I managed to reproduce this without -sMAIN_MODULE or -sEXPORT_ALL:

$ cat test.c
#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE void proc_exit(int status) { (void)status; }

int main() {}
$ ./emcc test.c -sSTANDALONE_WASM 
$ node ./a.out.js

The problem only seems to occur when the program itself tries to export the proc_exit function. In my example I use EMSCRIPTEN_KEEPALIVE to explicitly export it. In your example it gets exported due to -sMAIN_MODULE which exports every single symbol in your program.

Does your use case require -sMAIN_MODULE or could you get away with -sMAIN_MODULE=2 which only exports symbols needed by shared libraries. -sMAIN_MODULE=2 produces vastly smaller binaries so its highly recommended if you know what shared libraries you are planning on loading (you just pass them into the command line when linking your main module).

var77 commented 1 month ago

Thanks for the reply!

In my usecase I will dynamically load extension wasm files (with dlopen) and extensions may use any symbol from the main module.

What is the best way to proceed in this situation? Will the MAIN_MODULE=2 work in this case?