Skip to content

Commit 2701825

Browse files
authored
Report more undefined symbols at wasm-ld time (#21000)
Symbols that are part of EXPORTED_FUNCTIONS are now reported by wasm-ld.
1 parent 92eb422 commit 2701825

File tree

5 files changed

+37
-23
lines changed

5 files changed

+37
-23
lines changed

test/browser/test_sdl_key_proxy.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,3 @@ int main(int argc, char **argv) {
6464
emscripten_runtime_keepalive_push();
6565
return 0;
6666
}
67-

test/test_other.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,6 +2375,15 @@ def test_undefined_exported_function(self):
23752375
cmd = [EMXX, test_file('hello_world.cpp')]
23762376
self.run_process(cmd)
23772377

2378+
# adding a missing symbol to EXPORTED_FUNCTIONS should cause failure
2379+
cmd += ['-sEXPORTED_FUNCTIONS=_foobar']
2380+
err = self.expect_fail(cmd)
2381+
self.assertContained('wasm-ld: error: symbol exported via --export not found: foobar', err)
2382+
2383+
def test_undefined_exported_js_function(self):
2384+
cmd = [EMXX, test_file('hello_world.cpp')]
2385+
self.run_process(cmd)
2386+
23782387
# adding a missing symbol to EXPORTED_FUNCTIONS should cause failure
23792388
cmd += ['-sEXPORTED_FUNCTIONS=foobar']
23802389
err = self.expect_fail(cmd)
@@ -7226,7 +7235,7 @@ def test_no_warn_exported_jslibfunc(self):
72267235
err = self.expect_fail([EMCC, test_file('hello_world.c'),
72277236
'-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=alGetError',
72287237
'-sEXPORTED_FUNCTIONS=_main,_alGet'])
7229-
self.assertContained('error: undefined exported symbol: "_alGet" [-Wundefined] [-Werror]', err)
7238+
self.assertContained('wasm-ld: error: symbol exported via --export not found: alGet', err)
72307239

72317240
def test_musl_syscalls(self):
72327241
self.run_process([EMCC, test_file('hello_world.c')])
@@ -10074,7 +10083,7 @@ def test_dash_s_list_parsing(self):
1007410083
# stray slash
1007510084
('EXPORTED_FUNCTIONS=["_a", "_b",\\ "_c", "_d"]', 'undefined exported symbol: "\\\\ "_c"'),
1007610085
# missing comma
10077-
('EXPORTED_FUNCTIONS=["_a", "_b" "_c", "_d"]', 'emcc: error: undefined exported symbol: "_b" "_c" [-Wundefined] [-Werror]'),
10086+
('EXPORTED_FUNCTIONS=["_a", "_b" "_c", "_d"]', 'wasm-ld: error: symbol exported via --export not found: b" "_c'),
1007810087
]:
1007910088
print(export_arg)
1008010089
proc = self.run_process([EMCC, 'src.c', '-s', export_arg], stdout=PIPE, stderr=PIPE, check=not expected)

tools/building.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,20 +191,20 @@ def lld_flags_for_executable(external_symbols):
191191
c_exports = [e for e in settings.EXPORTED_FUNCTIONS if is_c_symbol(e)]
192192
# Strip the leading underscores
193193
c_exports = [demangle_c_symbol_name(e) for e in c_exports]
194-
c_exports += settings.EXPORT_IF_DEFINED
195194
# Filter out symbols external/JS symbols
196195
c_exports = [e for e in c_exports if e not in external_symbols]
196+
c_exports += settings.REQUIRED_EXPORTS
197197
if settings.MAIN_MODULE:
198198
c_exports += side_module_external_deps(external_symbols)
199199
for export in c_exports:
200-
cmd.append('--export-if-defined=' + export)
201-
202-
for export in settings.REQUIRED_EXPORTS:
203200
if settings.ERROR_ON_UNDEFINED_SYMBOLS:
204201
cmd.append('--export=' + export)
205202
else:
206203
cmd.append('--export-if-defined=' + export)
207204

205+
for e in settings.EXPORT_IF_DEFINED:
206+
cmd.append('--export-if-defined=' + e)
207+
208208
if settings.RELOCATABLE:
209209
cmd.append('--experimental-pic')
210210
cmd.append('--unresolved-symbols=import-dynamic')

tools/emscripten.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from tools.utils import exit_with_error, path_from_root, removeprefix
3232
from tools.shared import DEBUG, asmjs_mangle
3333
from tools.shared import treat_as_user_export
34-
from tools.settings import settings
34+
from tools.settings import settings, user_settings
3535

3636
sys.path.append(path_from_root('third_party'))
3737
import leb128
@@ -555,6 +555,7 @@ def finalize_wasm(infile, outfile, js_syms):
555555

556556
expected_exports = set(settings.EXPORTED_FUNCTIONS)
557557
expected_exports.update(asmjs_mangle(s) for s in settings.REQUIRED_EXPORTS)
558+
expected_exports.update(asmjs_mangle(s) for s in settings.EXPORT_IF_DEFINED)
558559
# Assume that when JS symbol dependencies are exported it is because they
559560
# are needed by by a JS symbol and are not being explicitly exported due
560561
# to EMSCRIPTEN_KEEPALIVE (llvm.used).
@@ -569,18 +570,21 @@ def finalize_wasm(infile, outfile, js_syms):
569570
unexpected_exports = [asmjs_mangle(e) for e in unexpected_exports]
570571
unexpected_exports = [e for e in unexpected_exports if e not in expected_exports]
571572

572-
# If `_main` was unexpectedly exported we assume it was added to
573-
# EXPORT_IF_DEFINED by emcc.py in order that we can detect it and
574-
# report this warning. In this case we explicitly ignore the export
575-
# and run as if there was no main function since that is defined is
576-
# behaviour for programs that don't include `_main` in EXPORTED_FUNCTIONS.
577-
if not settings.STANDALONE_WASM and '_main' in unexpected_exports:
578-
diagnostics.warning('unused-main', '`main` is defined in the input files, but `_main` is not in `EXPORTED_FUNCTIONS`. Add it to this list if you want `main` to run.')
579-
unexpected_exports.remove('_main')
580-
if 'main' in metadata.all_exports:
581-
metadata.all_exports.remove('main')
573+
if not settings.STANDALONE_WASM and 'main' in metadata.all_exports or '__main_argc_argv' in metadata.all_exports:
574+
if 'EXPORTED_FUNCTIONS' in user_settings and '_main' not in settings.USER_EXPORTED_FUNCTIONS:
575+
# If `_main` was unexpectedly exported we assume it was added to
576+
# EXPORT_IF_DEFINED by `phase_linker_setup` in order that we can detect
577+
# it and report this warning. After reporting the warning we explicitly
578+
# ignore the export and run as if there was no main function since that
579+
# is defined is behaviour for programs that don't include `_main` in
580+
# EXPORTED_FUNCTIONS.
581+
diagnostics.warning('unused-main', '`main` is defined in the input files, but `_main` is not in `EXPORTED_FUNCTIONS`. Add it to this list if you want `main` to run.')
582+
if 'main' in metadata.all_exports:
583+
metadata.all_exports.remove('main')
584+
else:
585+
metadata.all_exports.remove('__main_argc_argv')
582586
else:
583-
metadata.all_exports.remove('__main_argc_argv')
587+
unexpected_exports.append('_main')
584588

585589
building.user_requested_exports.update(unexpected_exports)
586590
settings.EXPORTED_FUNCTIONS.extend(unexpected_exports)

tools/link.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -810,11 +810,13 @@ def phase_linker_setup(options, state, newargs):
810810
# 2. If the user doesn't export anything we default to exporting `_main` (unless `--no-entry`
811811
# is specified (see above).
812812
if 'EXPORTED_FUNCTIONS' in user_settings:
813-
if '_main' not in settings.USER_EXPORTED_FUNCTIONS:
813+
if '_main' in settings.USER_EXPORTED_FUNCTIONS:
814+
settings.EXPORTED_FUNCTIONS.remove('_main')
815+
settings.EXPORT_IF_DEFINED.append('main')
816+
else:
814817
settings.EXPECT_MAIN = 0
815818
else:
816-
assert not settings.EXPORTED_FUNCTIONS
817-
settings.EXPORTED_FUNCTIONS = ['_main']
819+
settings.EXPORT_IF_DEFINED.append('main')
818820

819821
if settings.STANDALONE_WASM:
820822
# In STANDALONE_WASM mode we either build a command or a reactor.
@@ -838,7 +840,7 @@ def phase_linker_setup(options, state, newargs):
838840
# Note the exports the user requested
839841
building.user_requested_exports.update(settings.EXPORTED_FUNCTIONS)
840842

841-
if '_main' in settings.EXPORTED_FUNCTIONS:
843+
if '_main' in settings.EXPORTED_FUNCTIONS or 'main' in settings.EXPORT_IF_DEFINED:
842844
settings.EXPORT_IF_DEFINED.append('__main_argc_argv')
843845
elif settings.ASSERTIONS and not settings.STANDALONE_WASM:
844846
# In debug builds when `main` is not explicitly requested as an

0 commit comments

Comments
 (0)