Skip to content

Commit 9aa8ab3

Browse files
committed
support exceptions with virtual inheritance, by letting libcxxabi adjust the pointer as an out param; fixes #2531; 1.21.9
1 parent 9f5e322 commit 9aa8ab3

6 files changed

+57
-15
lines changed

emscripten-version.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
1.21.8
1+
1.21.9
22

src/library.js

+10-11
Original file line numberDiff line numberDiff line change
@@ -4010,28 +4010,27 @@ LibraryManager.library = {
40104010
if (throwntype == -1) throwntype = {{{ makeGetValue('header', 0, 'void*') }}};
40114011
var typeArray = Array.prototype.slice.call(arguments, 2);
40124012

4013-
// If throwntype is a pointer, this means a pointer has been
4014-
// thrown. When a pointer is thrown, actually what's thrown
4015-
// is a pointer to the pointer. We'll dereference it.
4016-
var thrownPtr = thrown;
4017-
if (throwntype != 0 && Module['___cxa_is_pointer_type'](throwntype)) {
4018-
var throwntypeInfoAddr= {{{ makeGetValue('throwntype', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}};
4019-
var throwntypeInfo= {{{ makeGetValue('throwntypeInfoAddr', '0', '*') }}};
4020-
if (throwntypeInfo == 0)
4021-
thrown = {{{ makeGetValue('thrown', '0', '*') }}};
4022-
}
4013+
assert(throwntype);
4014+
4015+
var pointer = Module['___cxa_is_pointer_type'](throwntype);
4016+
// can_catch receives a **, add indirection
4017+
if (!___cxa_find_matching_catch.buffer) ___cxa_find_matching_catch.buffer = _malloc(4);
4018+
{{{ makeSetValue('___cxa_find_matching_catch.buffer', '0', 'thrown', '*') }}};
4019+
thrown = ___cxa_find_matching_catch.buffer;
40234020
// The different catch blocks are denoted by different types.
40244021
// Due to inheritance, those types may not precisely match the
40254022
// type of the thrown object. Find one which matches, and
40264023
// return the type of the catch block which should be called.
40274024
for (var i = 0; i < typeArray.length; i++) {
4028-
if (typeArray[i] && Module['___cxa_can_catch'](typeArray[i], throwntype, thrown)) { // XXX thrown should be an out ptr
4025+
if (typeArray[i] && Module['___cxa_can_catch'](typeArray[i], throwntype, thrown)) {
4026+
thrown = {{{ makeGetValue('thrown', '0', '*') }}}; // undo indirection
40294027
{{{ makeStructuralReturn(['thrown', 'typeArray[i]']) }}};
40304028
}
40314029
}
40324030
// Shouldn't happen unless we have bogus data in typeArray
40334031
// or encounter a type for which emscripten doesn't have suitable
40344032
// typeinfo defined. Best-efforts match just in case.
4033+
thrown = {{{ makeGetValue('thrown', '0', '*') }}}; // undo indirection
40354034
{{{ makeStructuralReturn(['thrown', 'throwntype']) }}};
40364035
},
40374036

system/lib/libcxxabi/src/private_typeinfo.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -1162,13 +1162,15 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info,
11621162
#ifdef __EMSCRIPTEN__
11631163
extern "C" {
11641164

1165-
int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void *thrown) {
1165+
int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void **thrown) {
11661166
//std::type_info *t1 = static_cast<std::type_info*>(catchType);
11671167
//std::type_info *t2 = static_cast<std::type_info*>(excpType);
11681168
//printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown);
11691169

1170-
void *tempPtr = thrown; // XXX
1171-
return catchType->can_catch(excpType, tempPtr);
1170+
void *temp = *thrown;
1171+
int ret = catchType->can_catch(excpType, temp);
1172+
if (ret) *thrown = temp; // apply changes only if we are catching
1173+
return ret;
11721174
}
11731175

11741176
int __cxa_is_pointer_type(__shim_type_info* type) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <iostream>
2+
#include <stdexcept>
3+
4+
using std::cout;
5+
using std::endl;
6+
7+
struct my_exception : public virtual std::runtime_error {
8+
// To allow this to be thrown directly in the tests below.
9+
explicit my_exception(const std::string &what)
10+
: std::runtime_error(what)
11+
{}
12+
13+
protected:
14+
my_exception()
15+
// This won't be called because of virtual inheritance.
16+
: std::runtime_error("::my_exception")
17+
{}
18+
};
19+
20+
int main(const int argc, const char * const * const argv) {
21+
try {
22+
cout << "Throwing ::my_exception" << endl;
23+
throw ::my_exception("my_what");
24+
} catch(const std::runtime_error &ex) {
25+
cout << "Caught std::runtime_error: " << ex.what() << endl;
26+
}
27+
}
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Throwing ::my_exception
2+
Caught std::runtime_error: my_what

tests/test_core.py

+11
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,17 @@ def test_exceptions_typed(self):
14631463

14641464
self.do_run_from_file(src, output)
14651465

1466+
def test_exceptions_virtual_inheritance(self):
1467+
if self.emcc_args is None: return self.skip('requires emcc')
1468+
if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('needs fastcomp')
1469+
1470+
Settings.DISABLE_EXCEPTION_CATCHING = 0
1471+
1472+
test_path = path_from_root('tests', 'core', 'test_exceptions_virtual_inheritance')
1473+
src, output = (test_path + s for s in ('.cpp', '.txt'))
1474+
1475+
self.do_run_from_file(src, output)
1476+
14661477
def test_exceptions_multi(self):
14671478
Settings.DISABLE_EXCEPTION_CATCHING = 0
14681479
test_path = path_from_root('tests', 'core', 'test_exceptions_multi')

0 commit comments

Comments
 (0)