Skip to content

[EH] Print message for uncaught exceptions #18003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 10, 2022

Conversation

aheejin
Copy link
Member

@aheejin aheejin commented Oct 6, 2022

After #17979, when ASSERTIONS is set, uncaught exceptions carry stack traces that are printed to the screen for debugging help. This adds an exception message to the exception objects in addition to that.

The message it adds is produced by __get_exception_message function:

// Given a thrown_object, puts the information about its type and message into
// 'type' and 'message' output parameters. 'type' will contain the string
// representation of the type of the exception, e.g., 'int'. 'message' will
// contain the result of 'std::exception::what()' method if the type of the
// exception is a subclass of std::exception; otherwise it will be NULL. The
// caller is responsible for freeing 'type' buffer and also 'message' buffer, if
// it is not NULL.
void __get_exception_message(void* thrown_object, char** type, char** message) {
__cxa_exception* exception_header =
cxa_exception_from_thrown_object(thrown_object);
const __shim_type_info* thrown_type =
static_cast<const __shim_type_info*>(exception_header->exceptionType);
const char* type_name = thrown_type->name();
int status = 0;
char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status);
if (status == 0 && demangled_buf) {
*type = demangled_buf;
} else {
if (demangled_buf) {
free(demangled_buf);
}
*type = (char*)malloc(strlen(type_name) + 1);
strcpy(*type, type_name);
}
*message = NULL;
const __shim_type_info* catch_type =
static_cast<const __shim_type_info*>(&typeid(std::exception));
int can_catch = catch_type->can_catch(thrown_type, thrown_object);
if (can_catch) {
const char* what =
static_cast<const std::exception*>(thrown_object)->what();
*message = (char*)malloc(strlen(what) + 1);
strcpy(*message, what);
}
}

If an exception is a subclass of std::exception, it returns std::exception::what(). If not, it just prints its type.

If an exception is uncaught and its type is a subclass of std::exception, now we print the what() message along with the stack trace when ASSERTIONS is set. In case our exception is std::runtime_error and the message is "my exception", when uncaught, this prints:

exiting due to exception: [object WebAssembly.Exception],Error: std::runtime_error,my exception
    at __cxa_throw (wasm://wasm/009a7c9a:wasm-function[1551]:0x24367)
    ...

Fixes #6330.

After emscripten-core#17979, when `ASSERTIONS` is set, uncaught exceptions carry stack
traces that are printed to the screen for debugging help. This adds
an exception message to the exception objects in addition to that.

The message it adds is produced by `__get_exception_message` function:
https://github.com/emscripten-core/emscripten/blob/f6c46570e3780e52050bf822a07b342ec4bdddbe/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp#L75-L111

If an exception is a subclass of `std::exception`, it returns
`std::exception::what()`. If not, it just prints its type.

If an exception is uncaught and its type is a subclass of
`std::exception`, now we print the `what()` message along with the stack
trace when `ASSERTION` is set. In case our exception is
`std::runtime_error` and the message is "my exception", when uncaught,
this prints:
```
exiting due to exception: [object WebAssembly.Exception],Error:
std::runtime_error,my exception
    at __cxa_throw (wasm://wasm/009a7c9a:wasm-function[1551]:0x24367)
    ...
```

Fixes emscripten-core#6330.
@@ -293,7 +293,7 @@ __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) {
#else
// In debug mode, call a JS library function to use WebAssembly.Exception JS
// API, which enables us to include stack traces
__throw_exception_with_stack_trace(&exception_header->unwindHeader, true);
__throw_exception_with_stack_trace(&exception_header->unwindHeader);
Copy link
Member Author

@aheejin aheejin Oct 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This second argument is what I should've deleted in #17979 and forgot. (I first added an option in the JS f unction and then deleted it after feedback, but forgot to delete the caller side, which didn't error out)

@aheejin aheejin marked this pull request as draft October 6, 2022 08:14
@aheejin
Copy link
Member Author

aheejin commented Oct 6, 2022

Will convert this to a draft while fixing CI errors.

# Stack trace example for this example code:
# exiting due to exception: [object WebAssembly.Exception],Error
# Stack trace and message example for this example code:
# exiting due to exception: [object WebAssembly.Exception],Error: std::runtime_error, my message
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated, but I wonder if we could drop the [object WebAssembly.Exception], here. It seems to be just unnecessary visual noise.

Copy link
Member Author

@aheejin aheejin Oct 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think It's easy to consistently take out that part, because different engines can have different error formats. For example, d8 prints:

exiting due to exception: [object WebAssembly.Exception],Error: std::runtime_error,my message
    at __cxa_throw (wasm://wasm/00462286:wasm-function[44]:0x3b0f)
    at bar() (wasm://wasm/00462286:wasm-function[9]:0x98c)
    at foo() (wasm://wasm/00462286:wasm-function[10]:0x992)
    at __original_main (wasm://wasm/00462286:wasm-function[11]:0x9c4)
    at main (wasm://wasm/00462286:wasm-function[12]:0x9e1)
    at test.js:934:22
    at callMain (test.js:1874:15)
    at doRun (test.js:1928:23)
    at run (test.js:1943:5)

Whereas Node prints:

/usr/local/google/home/aheejin/test/stack/test.js:147
      throw ex;
      ^

WebAssembly.Exception: std::runtime_error,my message
    at __cxa_throw (wasm://wasm/00462286:wasm-function[44]:0x3b0f)
    at bar() (wasm://wasm/00462286:wasm-function[9]:0x98c)
    at foo() (wasm://wasm/00462286:wasm-function[10]:0x992)
    at __original_main (wasm://wasm/00462286:wasm-function[11]:0x9c4)
    at main (wasm://wasm/00462286:wasm-function[12]:0x9e1)
    at /usr/local/google/home/aheejin/test/stack/test.js:934:22
    at callMain (/usr/local/google/home/aheejin/test/stack/test.js:1874:15)
    at doRun (/usr/local/google/home/aheejin/test/stack/test.js:1928:23)
    at run (/usr/local/google/home/aheejin/test/stack/test.js:1943:5)

Node.js v17.5.0

So while both of them have WebAssembly.Exception, their printing formats differ, making taking it out in a consistent way difficult. We can just simply replace WebAssembly.Exception with an empty string, but not sure if that's better..?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving it as is sounds fine for to me then. We can attempt to refine in a followup perhaps.

Copy link
Collaborator

@RReverser RReverser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thanks!

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@aheejin aheejin marked this pull request as ready for review October 9, 2022 22:29
@aheejin aheejin merged commit 68a9f99 into emscripten-core:main Oct 10, 2022
@aheejin aheejin deleted the wasmeh_message branch October 10, 2022 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

throw exception with message in cpp
4 participants