Fail at link time if exception catching is enabled at compile time but not link time (#13862)

This commit is contained in:
Sam Clegg 2021-04-12 16:37:16 -07:00 коммит произвёл GitHub
Родитель e51a23f2cc
Коммит da39727384
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 49 добавлений и 21 удалений

Просмотреть файл

@ -143,6 +143,7 @@ var LibraryExceptions = {
return {{{ makeGetValue('this.ptr', 'ptrSize', '*') }}};
};
#if !DISABLE_EXCEPTION_CATCHING
// Get pointer which is expected to be received by catch clause in C++ code. It may be adjusted
// when the pointer is casted to some of the exception object base classes (e.g. when virtual
// inheritance is used). When a pointer is thrown this method should return the thrown pointer
@ -170,6 +171,7 @@ var LibraryExceptions = {
} else {
this.ptr = ptr;
}
#endif
},
$exception_addRef: function (info) {
@ -287,6 +289,7 @@ var LibraryExceptions = {
return type;
},
#if !DISABLE_EXCEPTION_CATCHING
__cxa_begin_catch__deps: ['$CatchInfo', '$exceptionCaught', '$exception_addRef',
'$uncaughtExceptionCount'],
__cxa_begin_catch: function(ptr) {
@ -336,6 +339,7 @@ var LibraryExceptions = {
#endif
return new CatchInfo(ptr).get_exception_ptr();
},
#endif
__cxa_uncaught_exceptions__deps: ['$uncaughtExceptionCount'],
__cxa_uncaught_exceptions: function() {
@ -371,6 +375,7 @@ var LibraryExceptions = {
___cxa_rethrow();
},
#if !DISABLE_EXCEPTION_CATCHING
// Finds a suitable catch clause for when an exception is thrown.
// In normal compilers, this functionality is handled by the C++
// 'personality' routine. This is passed a fairly complex structure
@ -380,7 +385,7 @@ var LibraryExceptions = {
// unwinding using 'if' blocks around each function, so the remaining
// functionality boils down to picking a suitable 'catch' block.
// We'll do that here, instead, to keep things simpler.
__cxa_find_matching_catch__deps: ['$exceptionLast', '$ExceptionInfo', '$CatchInfo', '__resumeException'],
__cxa_find_matching_catch__deps: ['$exceptionLast', '$ExceptionInfo', '$CatchInfo', '__resumeException', '__cxa_can_catch'],
__cxa_find_matching_catch: function() {
var thrown = exceptionLast;
if (!thrown) {
@ -440,8 +445,26 @@ var LibraryExceptions = {
catchInfo.free();
{{{ makeThrow('ptr') }}}
},
#endif
};
#if DISABLE_EXCEPTION_CATCHING
[
'__cxa_begin_catch',
'__cxa_end_catch',
'__resumeException',
'__cxa_find_matching_catch',
'__cxa_get_exception_ptr',
].forEach(function(name) {
LibraryExceptions[name] = function() { abort(); };
#if !INCLUDE_FULL_LIBRARY
LibraryExceptions[name + '__deps'] = [function() {
error('DISABLE_EXCEPTION_CATCHING was set, which means no C++ exception catching support code is linked in, but such support is required by symbol `' + name + '`. Either link with DISABLE_EXCEPTION_CATCHING=0 (if you do want exception catching) or compile all source files with DISABLE_EXCEPTION_CATCHING=1 (the default) (so that no exception catching support code is required).');
}];
#endif
});
#else
// In LLVM, exceptions generate a set of functions of form __cxa_find_matching_catch_1(), __cxa_find_matching_catch_2(), etc.
// where the number specifies the number of arguments. In Emscripten, route all these to a single function '__cxa_find_matching_catch'
// that variadically processes all of these functions using JS 'arguments' object.
@ -450,5 +473,6 @@ addCxaCatch = function(n) {
LibraryManager.library['__cxa_find_matching_catch_' + n + '__sig'] = new Array(n + 2).join('i');
LibraryManager.library['__cxa_find_matching_catch_' + n + '__deps'] = LibraryExceptions['__cxa_find_matching_catch__deps'];
};
#endif
mergeInto(LibraryManager.library, LibraryExceptions);

44
tests/test_other.py поставляемый
Просмотреть файл

@ -7210,7 +7210,7 @@ int main() {
self.assertEqual(wasm_data.count(b'dylink'), 1)
@is_slow_test
def test_wasm_backend_lto(self):
def test_lto(self):
# test building of non-wasm-object-files libraries, building with them, and running them
src = test_file('hello_libcxx.cpp')
@ -7243,10 +7243,10 @@ int main() {
self.assertContained('hello, world!', self.run_js('a.out.js'))
@parameterized({
'except': [],
'noexcept': ['-s', 'DISABLE_EXCEPTION_CATCHING=0']
'noexcept': [],
'except': ['-s', 'DISABLE_EXCEPTION_CATCHING=0']
})
def test_wasm_backend_lto_libcxx(self, *args):
def test_lto_libcxx(self, *args):
self.run_process([EMXX, test_file('hello_libcxx.cpp'), '-flto'] + list(args))
def test_lto_flags(self):
@ -9127,7 +9127,17 @@ int main(void) {
self.assertGreater(enable_size, disable_size)
self.assertEqual(disable_size, ignore_size)
def test_f_exception(self):
@parameterized({
# exceptions are off by default
'off': ([], [], False),
# enabling exceptions at link and compile works
'on': (['-fexceptions'], ['-fexceptions'], True),
# just compile isn't enough as the JS runtime lacks support
'compile_only': (['-fexceptions'], [], False),
# just link isn't enough as codegen didn't emit exceptions support
'link_only': ([], ['-fexceptions'], False),
})
def test_f_exception(self, compile_flags, link_flags, expect_caught):
create_file('src.cpp', r'''
#include <stdio.h>
int main () {
@ -9139,21 +9149,15 @@ int main(void) {
return 0;
}
''')
for compile_flags, link_flags, expect_caught in [
# exceptions are off by default
([], [], False),
# enabling exceptions at link and compile works
(['-fexceptions'], ['-fexceptions'], True),
# just compile isn't enough as the JS runtime lacks support
(['-fexceptions'], [], False),
# just link isn't enough as codegen didn't emit exceptions support
([], ['-fexceptions'], False),
]:
print(compile_flags, link_flags, expect_caught)
self.run_process([EMCC, 'src.cpp', '-c', '-o', 'src.o'] + compile_flags)
self.run_process([EMCC, 'src.o'] + link_flags)
result = self.run_js('a.out.js', assert_returncode=0 if expect_caught else NON_ZERO)
self.assertContainedIf('CAUGHT', result, expect_caught)
self.run_process([EMCC, 'src.cpp', '-c', '-o', 'src.o'] + compile_flags)
if compile_flags and not link_flags:
out = self.expect_fail([EMCC, 'src.o'] + link_flags)
self.assertContained('error: DISABLE_EXCEPTION_CATCHING was set, which means no C++ exception catching support code is linked in, but such support is required by symbol `__cxa_begin_catch`.', out)
return
self.run_process([EMCC, 'src.o'] + link_flags)
result = self.run_js('a.out.js', assert_returncode=0 if expect_caught else NON_ZERO)
self.assertContainedIf('CAUGHT', result, expect_caught)
def test_assertions_on_internal_api_changes(self):
create_file('src.c', r'''