Skip to content

Commit 081ebf2

Browse files
authored
[EH] Fix __get_exception_message for multiple inheritance (#24008)
#23552 added a routine to `__get_exception_message` so that in case of a dependent exception (i.e., a rethrown exception using `std::rethrow_exception`), it retrieves the correct primary exception's pointer to call `what()` on. But this turns out not to be correct in all cases, because `can_catch` can adjust the `thrown_object` pointer here: https://github.com/emscripten-core/emscripten/blob/ea8eda50e93d28876907bd6576c705478f1c35da/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp#L87-L94 Note that `adjustedPtr` parameter is a reference: https://github.com/emscripten-core/emscripten/blob/ea8eda50e93d28876907bd6576c705478f1c35da/system/lib/libcxxabi/src/private_typeinfo.h#L25-L26 It appears one of the cases that `thrown_object` pointer can be adjusted is when the caught exception is of a class that inherits from multiple classes. So in case of a dependent exception, if we just retrieve `reinterpret_cast<__cxa_dependent_exception*>(exception_header)->primaryException`, we lose the adjustment applied by `can_catch`. This calls `can_catch` again to make the necessary adjustment again in case of a dependent exception. Fixes #23733.
1 parent 91c9249 commit 081ebf2

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

system/lib/libcxxabi/src/cxa_exception_js_utils.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "cxa_exception.h"
66
#include "private_typeinfo.h"
7+
#include <assert.h>
78
#include <stdio.h>
89
// #include <stdint.h>
910
// #include <stdlib.h>
@@ -87,10 +88,15 @@ void __get_exception_message(void* thrown_object, char** type, char** message) {
8788
int can_catch = catch_type->can_catch(thrown_type, thrown_object);
8889
if (can_catch) {
8990
#if __WASM_EXCEPTIONS__
90-
if (isDependentException(&exception_header->unwindHeader))
91+
if (isDependentException(&exception_header->unwindHeader)) {
9192
thrown_object =
9293
reinterpret_cast<__cxa_dependent_exception*>(exception_header)
9394
->primaryException;
95+
// can_catch can adjust thrown_object ptr, so rerun it
96+
[[maybe_unused]] bool ret =
97+
catch_type->can_catch(thrown_type, thrown_object);
98+
assert(ret);
99+
}
94100
#endif
95101

96102
const char* what =

test/test_other.py

+31
Original file line numberDiff line numberDiff line change
@@ -9720,6 +9720,37 @@ def test_exceptions_exit_runtime(self):
97209720
self.set_setting('EXIT_RUNTIME')
97219721
self.do_other_test('test_exceptions_exit_runtime.cpp')
97229722

9723+
@with_all_eh_sjlj
9724+
def test_multi_inheritance_exception_message(self):
9725+
# Regression test for a bug that getting exception message in the DEBUG mode
9726+
# did not retrieve the correct thrown object pointer in case of multiple
9727+
# inheritance
9728+
create_file('src.cpp', r'''
9729+
#include <iostream>
9730+
9731+
struct Virt {
9732+
virtual void virt1() {}
9733+
};
9734+
9735+
struct MyEx : Virt, public std::runtime_error {
9736+
explicit MyEx(std::string msg) : std::runtime_error(std::move(msg)) {}
9737+
};
9738+
9739+
int main() {
9740+
try {
9741+
throw MyEx("ERROR");
9742+
} catch (...) {
9743+
try {
9744+
std::rethrow_exception(std::current_exception());
9745+
} catch (const std::exception &ex) {
9746+
std::cout << ex.what() << '\n';
9747+
}
9748+
}
9749+
}
9750+
''')
9751+
self.set_setting('ASSERTIONS')
9752+
self.do_runf('src.cpp', 'ERROR\n')
9753+
97239754
@requires_node
97249755
def test_jsrun(self):
97259756
print(config.NODE_JS)

0 commit comments

Comments
 (0)