Skip to content

Conversation

@juj
Copy link
Collaborator

@juj juj commented Oct 25, 2023

In #20534 the error message from the link produces an unhelpful

emscripten:ERROR: undefined symbol: __cxa_find_matching_catch_3 (referenced by top-level compiled C/C++ code) emscripten:ERROR: undefined symbol: __resumeException (referenced by top-level compiled C/C++ code) emscripten:ERROR: undefined symbol: llvm_eh_typeid_for (referenced by top-level compiled C/C++ code) 

In our huge Unity build system, I am likewise troubleshooting the same above errors, and also a separate build error with

Building Library\Bee\artifacts\WebGL\build\debug_WebGL_wasm\build.js failed with output: emscripten:ERROR: undefined symbol: emscripten_longjmp (referenced by top-level compiled C/C++ code) 

In a vast codebase that is built with several different build systems from external third party libraries, the above makes it impossible to understand where the source is coming from.

This PR improves Emscripten to report more helpful error messages:

emscripten:ERROR: undefined symbol: __cxa_find_matching_catch_3 (referenced by a.a:a.o) emscripten:ERROR: undefined symbol: __resumeException (referenced by a.a:a.o) emscripten:ERROR: undefined symbol: llvm_eh_typeid_for (referenced by a.a:a.o) 
Building Library\Bee\artifacts\WebGL\build\debug_WebGL_wasm\build.js failed with output: emscripten:ERROR: undefined symbol: emscripten_longjmp (referenced by C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.CoreModule_Dynamic.a:External_libtess2_libtess2_0_p6uvq.o,C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.ImageConversionModule_Dynamic.a:Modules_ImageConversion_0_rbqj9.o,C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.ImageConversionModule_Dynamic.a:External_libpng_src_1_7kqn7.o,C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.TextRenderingModule_Dynamic.a:ftbase_8zl7l.o,C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.TextRenderingModule_Dynamic.a:sfnt_0b4ju.o,C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.TextRenderingModule_Dynamic.a:otvalid_yeic4.o,C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.TextRenderingModule_Dynamic.a:smooth_9uxt4.o,C:/unity/build/WebGLSupport/BuildTools/lib/modules_development_wasm23/WebGLSupport_UnityPlayer.TextRenderingModule_Dynamic.a:External_libpng_src_1_7kqn7.o) 

that is a massive aid for the developer figure out where to go look at.

Needs a better solution than the settings.LINKER_INPUTS variable, feedback welcome. Also could not use shared.run_js_tool because it does not allow receiving stderr back.

@juj
Copy link
Collaborator Author

juj commented Oct 25, 2023

Btw, what is the status of longjmp support with Wasm exception handling? It looks like it is disabled by default, and I have to pair -fwasm-exceptions with -sEMSCRIPTEN_LONGJMP=1 to make it work with wasm exceptions?

@kripken
Copy link
Member

kripken commented Oct 25, 2023

Btw, what is the status of longjmp support with Wasm exception handling? It looks like it is disabled by default, and I have to pair -fwasm-exceptions with -sEMSCRIPTEN_LONGJMP=1 to make it work with wasm exceptions?

cc @aheejin

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach lgtm - LINKER_INPUTS seems reasonable to me actually (as an internal setting, I see no problem there).

logger.info('logging stderr in js compiler phase into %s' % stderr_file)
stderr_file = open(stderr_file, 'w')
else:
stderr_file = subprocess.PIPE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iiuc this stashes stderr so you can read it below, but I don't see you print it out later, so that means stderr is no longer visible to the user? There are warnings that come from the JS compiler that we need to show iirc.

@sbc100
Copy link
Collaborator

sbc100 commented Nov 7, 2023

I'm a little confused by this change since I've spent a lot of effort to get wasm-ld to report these errors precisely, so we should need this kind of thing:

$ cat test.c int foo(); int main() { return foo(); } $ emcc test.c wasm-ld: error: /tmp/emscripten_temp_8ag8qea2/test_0.o: undefined symbol: foo 

For a long time I had this behind LLD_REPORT_UNDEFINED but was recently able to make it the default. It even correctly reports errors from objects inside of library files. See test_unimplemented_syscalls in test_other.py:

self.assertContained('libc-debug.a(mincore.o): undefined symbol: __syscall_mincore', err) 

So in the general case I think this problem is already solved. There must be something about your build that is preventing wasm-ld from reporting these errors? Or there must be something specific about those symbols?

@sbc100
Copy link
Collaborator

sbc100 commented Nov 7, 2023

It looks like the LLD_REPORT_UNDEFINED change was back in 3.1.28:

3.1.28 - 12/08/22 ----------------- - `LLD_REPORT_UNDEFINED` is now enabled by default. This makes undefined symbol errors more precise by including the name of the object that references the undefined symbol. The old behaviour (of allowing all undefined symbols at wasm-ld time and reporting them later when processing JS library files) is still available using `-sLLD_REPORT_UNDEFINED=0`. (#16003) 

I think maybe the symbols in question are somehow special since they are generated by the compiler and this problem is solved for normal symbols. I think maybe if I can reproduce this then I can fix this on the llvm side. I'm hoping we can have wasm-ld be the one that reports all these errors in single place.

@sbc100
Copy link
Collaborator

sbc100 commented Nov 7, 2023

Yup, it looks like this is the issue in LLVM: https://github.com/llvm/llvm-project/blob/c3629923aa2c28c912a08556950e45225ddc8db7/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp#L449-L465

This assigns import names to these symbols which tells the linker to assume it can import them (and therefore assume they are defined). Perhaps we can remove this function completely.

@sbc100
Copy link
Collaborator

sbc100 commented Nov 7, 2023

Sorry for all the comments :)

Firstly this issue (IIUC) only effects the magic symbol related to exceptions and SJLJ and is not a widespread/general issue. I've got an llvm patch out that should fix this (at least for all the symbols listed in this bug): llvm/llvm-project#71599.

@aheejin
Copy link
Member

aheejin commented Nov 9, 2023

@juj

Btw, what is the status of longjmp support with Wasm exception handling? It looks like it is disabled by default, and I have to pair -fwasm-exceptions with -sEMSCRIPTEN_LONGJMP=1 to make it work with wasm exceptions?

Sorry for the delayed reply. The longjmp setting defaults to whatever EH setting you are using. So if you have -fwasm-exceptions, you don't need -sEMSCRIPTEN_LONGUMP additionally. It is not recommended to use mix different kinds of EH and SjLj modes.
https://emscripten.org/docs/porting/setjmp-longjmp.html#using-exceptions-and-setjmp-longjmp-together

sbc100 added a commit to sbc100/llvm-project that referenced this pull request Nov 10, 2023
…ated function declarations These days we would prefer that the linker report errors when these symbols are not defined. Assigning import names like this tells the linker not to report errors when these symbols are missing and simply import them. However, this leads to much less useful undefined symbol errors after the linker is done. Note that keep the old behavior for the `invoke_xxx` functions since its not possible for is to declare all possible permutations ahead of time in a library. See emscripten-core/emscripten#20536
@juj juj force-pushed the improve_c_to_js_undef_error_messages branch from 7366a34 to de80de4 Compare December 5, 2023 10:54
@juj
Copy link
Collaborator Author

juj commented Dec 5, 2023

Updated this PR now. Though I am a bit confused when writing a test for this.

In our Unity codebase we saw the C->JS linkage being handled by compiler.js, and hence getting those "referenced by top-level compiled C/C++ code" errors.

We are using Emscripten 3.1.38 there, so that should have had the change from 3.1.28.

I find in #19588 Sam changed the error message from

"referenced by top-level compiled C/C++ code"

into

"referenced by root reference (e.g. compiled C/C++ code)"

I am not completely sure how to coax that error path out now in order to add a test. I started trying with something like this, but that code flow does go to wasm-ld.

@sbc100
Copy link
Collaborator

sbc100 commented Dec 5, 2023

The reason I changed the error message from referenced by top-level compiled C/C++ code to referenced by root reference is that I was seeing this error due to command line flags such as -sEXPORTED_RUNTIME_METHODS and -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE.. which made the "C/C++ code" part confusing/incorrect.

@sbc100
Copy link
Collaborator

sbc100 commented Dec 5, 2023

I am not completely sure how to coax that error path out now in order to add a test. I started trying with something like this, but that code flow does go to wasm-ld.

Yes, this is exactly the hope. The idea is that wasm-ld will always give good error messages and there should be no need to parse its output or perform llvm-nm. At least that is my hope.

There were some recent improvements to error report for JS library symbol depenedencies made in #19843 which landed in 3.1.44.

There was also a specific fixes that I landed on the llvm side, relating to the internal SJLJ symbols: llvm/llvm-project#71599. I believe these were ones that were causing the problems in the orginal bug report above.

@sbc100
Copy link
Collaborator

sbc100 commented Dec 5, 2023

In other words, as far as I know, undefined symbols in native code should always now be reported by wasm-ld.

@juj
Copy link
Collaborator Author

juj commented Aug 16, 2025

Closing old stale PR.

@juj juj closed this Aug 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants