I have a cpp file test.cpp:
#include <stdio.h>
#include <iostream>
#include <emscripten/bind.h>
#include <emscripten/val.h>
int main()
{
throw std::invalid_argument("test error");
printf("\ndone\n");
return 0;
}
Compiled with emcc --bind -fexceptions -std=c++11 test.cpp -o test.js
I would like the code to print out the exception message in some way so the user has a description of the error.
When I run it I get exception thrown: 5246984 and Uncaught 5246984.
It does not appear as though emscripten will print any distinguishable message.
Does emscripten have this feature?
If not, I was thinking of adding a thow method to val that would accept a message and possibly a javascript exception class.
I don't think we have such a feature. In general I think people just add a try-catch at the highest level and print it from C++. If there's a way to add that feature it would be nice, but I'm not sure how easy it would be.
@kripken so there is no way of propagating the exception to js? Is there any way in which it could be wrapped or something?
I can't think of an easy way. But the thrown exception is a pointer, so in theory you could call from JS into C++ code like this, and give it that pointer:
// gets an exception object, and prints it out.
void print_exception(void* exception) {
try {
throw exception;
} catch (...) {
std::cout << exception.what() << '\n';
}
}
I think that might work, but I'm not sure.
ok, I didnt know that was an actual pointer!
I will play a bit with the idea and write back, thanks!
is it still open? i would like to know how to throw exception from c++ to js as well.
Hi, this is the current solution I use:
In C++:
namespace foo {
std::string getExceptionMessage(int exceptionPtr) {
return std::string(reinterpret_cast<std::exception *>(exceptionPtr)->what());
}
}
EMSCRIPTEN_BINDINGS(fooBinding) {
emscripten::function("getExceptionMessage", &foo::getExceptionMessage);
};
In JS:
try {
... // some code that calls webassembly
} catch (exception) {
console.error(Module.getExceptionMessage(exception));
} finally {
...
}
I guess you can also throw an exception from an EM_ASM block, if you wanted to rethrow c++ to JS.
Any updates?
I think adding an option like @Shachlan 's from the previous comment might be a good idea, if @Shachlan or someone else wants to submit a PR.
@kripken, sure. I'm not well versed in the Emscripten project organization - where would you prefer something like this to be added?
@Shachlan Good question, I'm not sure. Perhaps just adding an entry in the docs is enough, like in the debugging docs at ./site/source/docs/porting/Debugging.rst?
Printing exception.what() seems to be covered in this answer without needing to enable exception catching inside C++ and without using embind:
https://stackoverflow.com/a/33743704/581848
This post explains why exception catching at the C++ level kills performance under wasm:
https://brionv.com/log/2019/10/24/exception-handling-in-emscripten-how-it-works-and-why-its-disabled-by-default/
For the purposes of unit testing C++ compiled with emscripten and run under node.js, which does not have window.onerror like the browser solutions above, I was attempting to use something like this:
struct Exception{
static std::string what(intptr_t p){
return reinterpret_cast<std::runtime_error*>(p)->what();
}
/**ctor*/
Exception(){
#ifdef __EMSCRIPTEN__
EM_ASM(({
console.log("This gets called and gives false:",
process.hasUncaughtExceptionCaptureCallback()
);
//window.addEventListener('error',
//process['on']('unhandledRejection',
//process['on']('uncaughtExceptionMonitor',
process['on']('uncaughtException',
()=>{console.log("This never gets called.");
console.error(Module.Exception.what(e.error));
});
}),0);
#endif
};
};
#ifdef __EMSCRIPTEN__
EMSCRIPTEN_BINDINGS(CRANE){
emscripten::class_<Exception>("Exception")
.class_function("what",&Exception::what);
}
#endif
I instantiate it as a C++ static variable inside the ctor body of another class I wrote for setting up and running tests, so that Exception() only gets called once, and thus only after main. However, in node.s, the console.log inside uncaughtException will never get printed. I always get something like what the original poster received: exception thrown: 5246984
I believe the reason why is as follows. In parseTools.js, the function makeThrow(what) returns a string 'throw' + what + ';', where what seems to come from one of three spots in library_exceptions.js and is the address of the exception (i.e. the value of the pointer). So, I created a simple one-line node.js script where I threw a number to replicate this behavior, and its output was completely different:
C:\msys64\home\chris.chiasson\wCRANE>node tmp/tmp.js
C:\msys64\home\chris.chiasson\wCRANE\tmp\tmp.js:1
throw 593485;
^
593485
I am also able to catch that throw via process.on('uncaughtException',...). So, knowing the weird behavior was not coming from node itself, I grepped all of the emsdk folder for exception thrown, and three spots stood out, along with two commits.
Essentially, these code structures in Emscripten are preventing the global error handlers in node from ever firing. In my opinion, one way to solve it would be to actually register Emscripten's top level error handlers using the node.js process.on mechanism (or window.addEventListener in-brower). That way, Emscripten's handlers would still fire, but we would also be free to add our own straight from within our c++ unit tests and makefiles without any other special steps or source files required (other than prefixing Emscripten wasm/javascript unit tests with the name of the node executable, whereas in straight C++, we'd call the executable directly). This would also prevent the added complexity of integrating emrun and the browser into standard unit tests. What do y'all think?
Most helpful comment
Hi, this is the current solution I use:
In C++:
In JS:
I guess you can also throw an exception from an
EM_ASMblock, if you wanted to rethrow c++ to JS.