2

I was trying to use setjmp/longjmp on a C++ project compiled with emscripten (version 1.39.16-fastcomp, can't use WebAssembly), and I came across instances of the program crashing after longjmp. I tried compiling in WebAssembly just for reference and the crash went away, so it looks like a bug on emscripten side. Maybe someone can provide a workaround.

Here's a snippet that reproduces the bug:

#include <cstdlib>
#include <cstdio>
#include <csetjmp>
#include <emscripten.h>

jmp_buf buffer;
int iterations;

void check() {
  emscripten_sleep(100);
  if (iterations < 10) {
    printf("~ jump attempt ~\n");
    longjmp(buffer, 1);
  }
}

void run() {
  printf("%d\n", iterations);
  check();
}

int main() {
  if (setjmp(buffer) == 0) {
    iterations = 0;
  } else {
    iterations++;
  }
  run();
  return 0;
}

And here are the flags used for compilation: emcc -O0 -s EMTERPRETIFY=1 -s EMTERPRETIFY_ASYNC=1 -s WASM=0 c.cpp -o c.js

In essence, longjmp() is used to increment the counter, and the program should enumerate the numbers from 0 to 10 with "~ jump attempt ~" mixed in between.

However, when running c.js with node, I get the following output:

0
~ jump attempt ~
1
undefined
undefined

/Users/tsr/dev/c.js:89
   throw ex;
   ^
abort(undefined) at Error
    at jsStackTrace
    at stackTrace
    at abort
    at emterpAssert
    at emterpret
    at emterpret
    at _setThrew
    at asm._setThrew
    at _longjmp
    at emterpret
This error happened during an emterpreter-async operation. Was there non-emterpreted code
on the stack during save (which is unallowed)? If so, you may want to adjust
EMTERPRETIFY_BLACKLIST, EMTERPRETIFY_WHITELIST. For reference, this is what the stack
looked like when we tried to save it: 2,Error
    at Object.handle
    at _emscripten_sleep
    at emterpret
    at emterpret
    at emterpret
    at Array.__Z3runv
    at dynCall_v
    at invoke_v
    at emterpret
    at Object.asm.emterpret
make: *** [c.js_run] Error 7

The first call to longjmp() seems to have worked, since the number "1" was printed, but then the program crashes somewhere in the emscripten_sleep (adding prints around the call makes it certain).

I'm quite puzzled as to why this does not work, especially since there are other setjmp/longjmp constructs that EMTERPRETER is capable of handling perfectly well.

Clifford
  • 88,407
  • 13
  • 85
  • 165
teehessar
  • 21
  • 3
  • Are you mixing javascript and C++? Mixing languages makes a project more difficult to write and maintain. I recommend programming in JavaScript **OR** C++. You should pick one and update your language tags. Does JavaScript have the `setjmp` function? – Thomas Matthews Jun 18 '21 at 15:21
  • https://github.com/numworks/epsilon/issues/1735 - see the answer. setjmp/longjmp are nasty in a normal C++ runtime, I'd be amazed if this were reliably supported. It may be better to explain what it is you are trying to achieve - perhaps that is a more appropriate mechanism. – Clifford Jun 18 '21 at 15:24
  • 1
    The original codebase is in C++, and is ported to the web with emscripten. Technically we never write a single line of js ; when emscripten works there is no need to. setjmp is supported in theory, as long as you don't try to be dirty and jump to an unwound stack you restored by hand... – teehessar Jun 18 '21 at 15:30
  • 1
    @ThomasMatthews : It is new to me, but Emscripterm is a C++ to WebAssembly tool; I think the JavaScript element is a necessary component. From the documentation "_Emscripten build output consists of two essential parts: 1) the low level compiled code module and **2) the JavaScript runtime to interact with it.**_". It does not mean he is attempting JS/C++ interop. – Clifford Jun 18 '21 at 15:34
  • @Clifford, I also came across this repo, and they make use of micropython which uses setjmp/longjmp for its exception handling on the web. Since there doesn't seem to be any problem with those, I figured setjmp must be somewhat supported. – teehessar Jun 18 '21 at 15:38

0 Answers0