Description
We have a codebase that gives a RuntimeError on iOS 18 Safari when compiled with -fwasm-exceptions
. The same code with -fexceptions
works fine. The -fwasm-exceptions
build also works correctly on other browsers, platforms, and iOS versions.
I was able to reproduce this with the iOS 18.0 simulator running on an Apple Silicon Mac.
Here are some test links that demonstrate the behaviour difference between the exception modes when run on iOS 18.0:
JS: https://tango-bravo.net/zcvjs_exception_tests/js_SIMD_False/js_SIMD_False.html
WASM: https://tango-bravo.net/zcvjs_exception_tests/native_SIMD_False/native_SIMD_False.html
The top one runs to completion whereas the bottom one throws this RuntimeError midway through:
RuntimeError: call_indirect to a null table entry

NB: Both versions will have a console error when they try to upload performance results, this code was intended to be used from a local server that would handle the upload.
Simple cases (such as the example from https://emscripten.org/docs/porting/exceptions.html) works fine in both modes:
JS: https://tango-bravo.net/zcvjs_exception_tests/simple_throw_catch/js-exceptions.html
WASM: https://tango-bravo.net/zcvjs_exception_tests/simple_throw_catch/wasm-exceptions.html
I've also checked iOS simulators for 17.4, 17.5, 18.1 and 18.2 and this appears to be limited to 18.0.
I haven't been able to track down a build of Safari 18.0 for Mac so I haven't tested there. Seems AWS have an AMI image of macOS 15.0 which would probably ship with Safari 18.0 but I don't want to pay the minimum 24 hour reservation just for testing this.
The links I have shared for the builds were made last year but we can probably track down the commit and try building with different flags / emscripten versions etc if there's interest in trying to dig more into it.
The exceptions causing the issue stem from the gtsam project - https://github.com/borglab/gtsam - it's in template code and uses exceptions to step back during a Levenberg-Marquadt numerical optimisation, and there's possibly quite a lot of stuff on the stack that will need cleaning up as part of handling the exception. It's not a particularly minimal reproducer I'm afraid - we spent some time trying to get a more minimal test case but then discovered JS exceptions with the allowlist offered similar performance and didn't suffer from the issue, so we moved over to that instead.
We have previously seen Safari applying stricter limits on stack depth than other runtimes but at least from the exception stack that doesn't seem to be the case here.