Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
var77 opened this issue Jul 9, 2024 · 4 comments
Open

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

var77 opened this issue Jul 9, 2024 · 4 comments

Comments

@var77
Copy link

var77 commented Jul 9, 2024

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
Copy link
Collaborator

sbc100 commented Jul 10, 2024

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
Copy link
Collaborator

sbc100 commented Jul 10, 2024

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
Copy link
Author

var77 commented Jul 11, 2024

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?

@sbc100
Copy link
Collaborator

sbc100 commented Feb 8, 2025

I think fixing this issue (native symbols conflicting with JS library symbols) is going to be hard to solve.

To use MAIN_MODULE=2 you would need to list all the symbols that you want to share with your side modules. You can put them in a file called symbols.txt and then use -sEXPORTED_FUNCTIONS=@symbols.txt. Or I think you maybe able to take the symbols at the source level (using something like DLL_EXPORT), although I'm not totally sure about that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants