> While writing this mail,I realised a possible short-cut to let me get the test harness > running more quickly, without having to generate a wrapper for hundreds of different > functions, with thousands of associated data types and constants. It goes like this: > > The calls to the library from the test harness are generated by C macros, and I can > add code to those for the WebAssembly build. So it appears I could use EM_ASM() > to create JavaScript error handlers at each of those call sites, as part of the test > harness source. I could then statically link the library and the test harness for running > tests. Is that plausible?
Over the weekend I realised the difficulty with that: I'd have to get all the arguments into JavaScript variables, pass them into the calls inside the try/catch blocks, and then get them back into Emscripten C/C++ variables. Since they contain loads of arrays, C struts and strings, this amounts to generating a wrapper anyway. Alternatively, will catching exceptions with -fwasm-exceptions allow me to catch out-of-bounds exceptions in Emscripten-compiled C++? Thanks in advance, John On Fri, Sep 12, 2025 at 4:02 PM John Dallman <[email protected]> wrote: > > OK, what I want to do isn't possible in Emscripten. > > It looks like it is, actually, but it's a bit complicated. Here's the > scheme: am I requiring anything that doesn't exist? > > I have a great big math library that I want to make available in > WebAssembly form, as a commercial product. It is written in C and C++, and > runs on Android, iOS, Linux, macOS and Windows. Its heritage is from 1980s > and 1990s technical computing, but it is still going strong as a commercial > product. The immediate customers for it want to call it from C/C++ code > that they already use on other platforms (mostly Linux and Windows), rather > than from JavaScript. > > This math library has a test harness, also written in C and C++. The test > cases are *not* written in C/C++, but in interpreted LISP, because that's > quite suitable for handling the data that the library works with, plus it > was easy to write our own portable implementation of the language. > > When you run the test harness, it looks for a LISP file to run and starts > interpreting it, which usually starts by reading a lot more LISP files to > set up a working environment. It then starts reading test scripts and > making the calls to the math library that they request. The test harness > does not exit until it has finished running everything it was given, or it > hits an unrecoverable error. On its existing platforms, it can recover from > SIGSEGV, SIGPFE, and other run-time errors, aborting the test that caused > them and continuing with the subsequent test(s). > > That last part is the problem with a naive WebAssembly implementation, > where the library and the test harness are statically linked together. That > means there's no opportunity for a JavaScript error handler to get involved > before exceptions caused by access violations come flying out of the top of > the test harness. By then, the call stack is gone, and there's no way to > recover from the exception and continue with the next test. > > That's where I'd got to when I wrote " . . . what I want to do isn't > possible in Emscripten." I've had what seem like better ideas since then. > > WebAssembly "modules" are, as far as I understand, kind of like Windows > DLLs or Linux shared libraries. There's a difference in that you can't link > a module against other modules: inter-module calls have to go via > JavaScript. Is that correct? > > I was slow to realise that I can put JavaScript error handlers into any > JavaScript layer. To take advantage of that, I would link my math library > as a module, and its test harness as the main program. The test harness > would call JavaScript code, which would call the library from within a > try/catch block, catch exceptions, call the library's "tidy up" functions, > and return an error code to the test harness. That lets the test harness > recover from exceptions and move on to the next test. It also means I need > to create a JavaScript wrapper for the whole of the library's API, which is > a bit of a big job, but makes the library more generally usable in > WebAssembly code. > > While writing this mail,I realised a possible short-cut to let me get the > test harness running more quickly, without having to generate a wrapper for > hundreds of different functions, with thousands of associated data types > and constants. It goes like this: > > The calls to the library from the test harness are generated by C macros, > and I can add code to those for the WebAssembly build. So it appears I > could use EM_ASM() to create JavaScript error handlers at each of those > call sites, as part of the test harness source. I could then statically > link the library and the test harness for running tests. Is that plausible? > > Thanks in advance, > > John > > > > > On Thu, Sep 11, 2025 at 3:00 PM John Dallman <[email protected]> > wrote: > >> OK, what I want to do isn't possible in Emscripten. >> >> Thanks, everyone. >> >> John >> >> On Tue, Sep 9, 2025 at 7:37 AM Heejin Ahn <[email protected]> wrote: >> >>> Correct. Both Emscripten and Wasm SjLj handling requires the setjmp >>> point to be "lower" than the longjmp point, because both use exceptions to >>> simulate setjmp-longjmp. >>> So this works: >>> ``` >>> static jmp_buf buf; >>> >>> void bar() { >>> } >>> >>> int main() { >>> int jmpval = setjmp(buf); >>> if (jmpval == 0) { >>> printf("first call\n"); >>> } else { >>> printf("second call\n"); >>> exit(0); >>> } >>> bar(); >>> return 0; >>> } >>> ``` >>> >>> But this does NOT work: >>> ``` >>> static jmp_buf buf; >>> >>> void foo() { >>> int jmpval = setjmp(buf); >>> if (jmpval == 0) { >>> printf("first call\n"); >>> } else { >>> printf("second call\n"); >>> exit(0); >>> } >>> } >>> >>> void bar() { >>> longjmp(buf, 1); >>> } >>> >>> int main() { >>> foo(); >>> bar(); >>> return 0; >>> } >>> ``` >>> >>> Because by the time longjmp is called, foo's call stack has been >>> destroyed. >>> >>> On Mon, Sep 8, 2025 at 4:31 PM 'Sam Clegg' via emscripten-discuss < >>> [email protected]> wrote: >>> >>>> If you want to use `longjmp` in emscripten to get back to start of the >>>> failing test, we have two setjmp/longjmp mechanism. (1) The old emscripten >>>> method (2) The method using wasm exception handling. >>>> >>>> However, I believe that in both cases the target of the long jump has >>>> to be above the caller on the stack. That is, once you unwind the stack >>>> all of the way it will no longer be possible to `longjmp` to the target in >>>> question since its no longer on the stack. @Heejin Ahn >>>> <[email protected]> can you confirm this? >>>> >>>> If that is correct then you will need to some kind of alternative >>>> mechanism when running in emscrpten. Something like this maybe: >>>> >>>> ``` >>>> void run_death_test(death_test_fn_t fn) { >>>> #ifdef __EMSCRIPTEN__ >>>> EM_ASM({ >>>> try { >>>> ...call_fn_from_js.. >>>> report_failure_to_die() >>>> } catch (e) { >>>> report_success_if_e_looks_good(e) >>>> } >>>> }) >>>> #else >>>> setup_longjmp_target(): >>>> fn(); >>>> #endif >>>> } >>>> ``` >>>> >>>> On Mon, Sep 8, 2025 at 4:17 PM Sam Clegg <[email protected]> wrote: >>>> >>>>> >>>>> >>>>> On Mon, Sep 8, 2025 at 3:40 AM John Dallman <[email protected]> >>>>> wrote: >>>>> >>>>>> > Is the test harness and the library-under-test designed to be >>>>>> compiled into the >>>>>> > same executable? >>>>>> >>>>>> Yes. We prefer to have the library-under-test be a shared object or >>>>>> Windows DLL, on platforms where that's possible, but we can have the >>>>>> harness and the library linked together, and that's what I'm planning to >>>>>> do >>>>>> for WebAssembly. I'm trying to avoid producing a JS wrapper for an API >>>>>> with >>>>>> hundreds of functions, hundreds of structs, and thousands of constants. >>>>>> It >>>>>> also passes lots of pointers to code and data through the interface. My >>>>>> customers who want a WebAssembly version of the library already have >>>>>> C/C++ >>>>>> or Swift code that calls it and want to use it that way. >>>>>> >>>>>> > i.e. on other platforms does it somehow catch and recover from >>>>>> sefaults? >>>>>> >>>>>> Yes.On platforms with signals, those are turned on for segmentation >>>>>> faults (and for some other signals, depending on the platform). The code >>>>>> is >>>>>> C, which sets regular checkpoints with setjmp() and the signal handling >>>>>> function longjmp()s to the latest checkpoint with a "test aborted" value. >>>>>> That's the basic idea, though it's rather more complicated in practice. >>>>>> >>>>> >>>>> Oh wow, `longjmp` out of your signal handler sounds pretty gnarly. >>>>> It's going to be even more gnarly trying to make that work with >>>>> emscripten-generated code, but maybe not impossible? >>>>> >>>>> Are there segfault tests limited in number? i.e. would it be possible >>>>> to choose a different approach when running on the web (just for these few >>>>> tests)? >>>>> >>>>>> >>>>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "emscripten-discuss" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to [email protected]. >>>> To view this discussion visit >>>> https://groups.google.com/d/msgid/emscripten-discuss/CAL_va29WgYahkgoafxhXGs%2BPhfpP-o6GzQSgaTA3xRGhdPKRNg%40mail.gmail.com >>>> <https://groups.google.com/d/msgid/emscripten-discuss/CAL_va29WgYahkgoafxhXGs%2BPhfpP-o6GzQSgaTA3xRGhdPKRNg%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "emscripten-discuss" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to [email protected]. >>> To view this discussion visit >>> https://groups.google.com/d/msgid/emscripten-discuss/CALJpS1Nzcxx0mzS%2BxHTxrETvyGiuppeOcz68PNdjwNtYaG0YcA%40mail.gmail.com >>> <https://groups.google.com/d/msgid/emscripten-discuss/CALJpS1Nzcxx0mzS%2BxHTxrETvyGiuppeOcz68PNdjwNtYaG0YcA%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> >> -- You received this message because you are subscribed to the Google Groups "emscripten-discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/emscripten-discuss/CAH1xqgkGzfdwUdTLxNK6LMBHdG0Kat4HSxiLeB12JBe8UJEqqA%40mail.gmail.com.
