Skip to content

Commit ddd7489

Browse files
authored
Return a pair [type, what] from getExceptionMessage (#17386)
As discussed in #17362, this changes `getExceptionMessage` to return a pair, the exception type and the exception `what()` if available. If no exception description is available, the second entry will be undefined. This is an API break so we may want to give the new function a different name and keep the old one or something. The behavior of `__get_exception_terminate_message` should be unchanged. This change adds a few extra heap allocations but this is not supposed to be hot code.
1 parent 57c61a5 commit ddd7489

File tree

3 files changed

+66
-39
lines changed

3 files changed

+66
-39
lines changed

src/library_exceptions.js

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,26 @@ var LibraryExceptions = {
393393
},
394394

395395
#endif
396+
#if WASM_EXCEPTIONS || !DISABLE_EXCEPTION_CATCHING
397+
$getExceptionMessageCommon__deps: ['__get_exception_message', 'free'],
398+
$getExceptionMessageCommon: function(ptr) {
399+
return withStackSave(function() {
400+
var type_addr_addr = stackAlloc(4);
401+
var message_addr_addr = stackAlloc(4);
402+
___get_exception_message(ptr, type_addr_addr, message_addr_addr);
403+
var type_addr = HEAP32[type_addr_addr >> 2];
404+
var message_addr = HEAP32[message_addr_addr >> 2];
405+
var type = UTF8ToString(type_addr);
406+
_free(type_addr);
407+
var message;
408+
if (message_addr) {
409+
message = UTF8ToString(message_addr);
410+
_free(message_addr);
411+
}
412+
return [type, message];
413+
});
414+
},
415+
#endif
396416
#if WASM_EXCEPTIONS
397417
$getCppExceptionTag: function() {
398418
return Module['asm']['__cpp_exception'];
@@ -423,15 +443,10 @@ var LibraryExceptions = {
423443
___cxa_decrement_exception_refcount(ptr);
424444
},
425445

426-
$getExceptionMessage__deps: ['__get_exception_message', 'free', '$getCppExceptionThrownObjectFromWebAssemblyException'],
446+
$getExceptionMessage__deps: ['$getCppExceptionThrownObjectFromWebAssemblyException', '$getExceptionMessageCommon'],
427447
$getExceptionMessage: function(ex) {
428-
// In Wasm EH, the thrown object is a WebAssembly.Exception. Extract the
429-
// thrown value from it.
430448
var ptr = getCppExceptionThrownObjectFromWebAssemblyException(ex);
431-
var utf8_addr = ___get_exception_message(ptr);
432-
var result = UTF8ToString(utf8_addr);
433-
_free(utf8_addr);
434-
return result;
449+
return getExceptionMessageCommon(ptr);
435450
},
436451

437452
#elif !DISABLE_EXCEPTION_CATCHING
@@ -444,14 +459,12 @@ var LibraryExceptions = {
444459
$decrementExceptionRefcount: function(ptr) {
445460
___cxa_decrement_exception_refcount(ptr);
446461
},
447-
448-
$getExceptionMessage__deps: ['__get_exception_message', 'free'],
462+
$getExceptionMessage__deps: ['$getExceptionMessageCommon'],
449463
$getExceptionMessage: function(ptr) {
450-
var utf8_addr = ___get_exception_message(ptr);
451-
var result = UTF8ToString(utf8_addr);
452-
_free(utf8_addr);
453-
return result;
464+
return getExceptionMessageCommon(ptr);
454465
},
466+
467+
455468
#endif
456469
};
457470

system/lib/libcxxabi/src/cxa_exception_emscripten.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <stdio.h>
1414
#include <stdint.h>
1515
#include <stdlib.h>
16+
#include <string.h>
1617

1718
#if !defined(__USING_WASM_EXCEPTIONS__)
1819
// Until recently, Rust's `rust_eh_personality` for emscripten referred to this
@@ -71,7 +72,14 @@ void* __thrown_object_from_unwind_exception(
7172
return thrown_object_from_unwind_exception(unwind_exception);
7273
}
7374

74-
char* __get_exception_message(void* thrown_object, bool terminate=false) {
75+
// Given a thrown_object, puts the information about its type and message into
76+
// 'type' and 'message' output parameters. 'type' will contain the string
77+
// representation of the type of the exception, e.g., 'int'. 'message' will
78+
// contain the result of 'std::exception::what()' method if the type of the
79+
// exception is a subclass of std::exception; otherwise it will be NULL. The
80+
// caller is responsible for freeing 'type' buffer and also 'message' buffer, if
81+
// it is not NULL.
82+
void __get_exception_message(void* thrown_object, char** type, char** message) {
7583
__cxa_exception* exception_header =
7684
cxa_exception_from_thrown_object(thrown_object);
7785
const __shim_type_info* thrown_type =
@@ -81,38 +89,44 @@ char* __get_exception_message(void* thrown_object, bool terminate=false) {
8189
int status = 0;
8290
char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status);
8391
if (status == 0 && demangled_buf) {
84-
type_name = demangled_buf;
92+
*type = demangled_buf;
93+
} else {
94+
if (demangled_buf) {
95+
free(demangled_buf);
96+
}
97+
*type = (char*)malloc(strlen(type_name) + 1);
98+
strcpy(*type, type_name);
8599
}
86100

101+
*message = NULL;
87102
const __shim_type_info* catch_type =
88103
static_cast<const __shim_type_info*>(&typeid(std::exception));
89104
int can_catch = catch_type->can_catch(thrown_type, thrown_object);
90-
char* result = NULL;
91105
if (can_catch) {
92106
const char* what =
93107
static_cast<const std::exception*>(thrown_object)->what();
94-
asprintf(&result,
95-
(terminate ? "terminating with uncaught exception of type %s: %s"
96-
: "exception of type %s: %s"),
97-
type_name,
98-
what);
99-
} else {
100-
asprintf(&result,
101-
(terminate ? "terminating with uncaught exception of type %s"
102-
: "exception of type %s"),
103-
type_name);
108+
*message = (char*)malloc(strlen(what) + 1);
109+
strcpy(*message, what);
104110
}
111+
}
105112

106-
if (demangled_buf) {
107-
free(demangled_buf);
113+
// Returns a message saying that execution was terminated due to an exception.
114+
// This message is freshly malloc'd and should be freed.
115+
char* __get_exception_terminate_message(void* thrown_object) {
116+
char* type;
117+
char* message;
118+
__get_exception_message(thrown_object, &type, &message);
119+
char* result;
120+
if (message != NULL) {
121+
asprintf(
122+
&result, "terminating with uncaught exception %s: %s", type, message);
123+
free(message);
124+
} else {
125+
asprintf(&result, "terminating with uncaught exception of type %s", type);
108126
}
127+
free(type);
109128
return result;
110129
}
111-
112-
char* __get_exception_terminate_message(void *thrown_object) {
113-
return __get_exception_message(thrown_object, true);
114-
}
115-
116130
}
117131

118132
#endif // __USING_EMSCRIPTEN_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__

tests/test_core.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,19 +1681,19 @@ class myexception : public exception {
16811681
// __cxa_end_catch. Fix this inconsistency later.
16821682
incrementExceptionRefcount(p);
16831683
#endif
1684-
console.log(getExceptionMessage(p));
1684+
console.log(getExceptionMessage(p).toString());
16851685
decrementExceptionRefcount(p);
16861686
}
16871687
}
16881688
});
16891689
}
16901690
'''
16911691
expected = '''\
1692-
exception of type int
1693-
exception of type char
1694-
exception of type std::runtime_error: abc
1695-
exception of type myexception: My exception happened
1696-
exception of type char const*
1692+
int,
1693+
char,
1694+
std::runtime_error,abc
1695+
myexception,My exception happened
1696+
char const*,
16971697
'''
16981698

16991699
self.do_run(src, expected)

0 commit comments

Comments
 (0)