Skip to content
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

Add helper function for C++ exception formatting #16343

Merged
merged 30 commits into from
Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3cf21a0
Wrote format_exception function and hard coded inclusion into system_…
hoodmane Feb 18, 2022
2ea06c8
Add Javascript wrapper, miscellaneous cleanup
hoodmane Feb 19, 2022
693f677
Fix formatting
hoodmane Feb 19, 2022
95ef456
No need for exportedAsmFunction
hoodmane Feb 20, 2022
103dca8
Use withStackSave
hoodmane Feb 20, 2022
cc31016
Free the right thing
hoodmane Feb 20, 2022
5ca4f18
Use stackAlloc({{{ POINTER_SIZE }}});
hoodmane Feb 20, 2022
aa15cc8
Remove accidental change
hoodmane Feb 20, 2022
493e22f
Add final newline to format_exception.cpp
hoodmane Feb 20, 2022
c7d1267
Add emscripten_ prefix to format_exception
hoodmane Feb 20, 2022
0231037
Add format_exception.cpp to libcxxabi
hoodmane Feb 20, 2022
af456b1
Use withStackSave correctly
hoodmane Feb 20, 2022
e233943
Remove libformatexception library
hoodmane Feb 20, 2022
83a1a4a
Various fixes
hoodmane Feb 20, 2022
5e765ab
Add test
hoodmane Feb 20, 2022
1235600
Remove addresses from test comparison
hoodmane Feb 20, 2022
a83007e
Try to fix test
hoodmane Feb 21, 2022
5f19ef5
Fix wasm-exceptions test
hoodmane Feb 21, 2022
86b703b
Fix test
hoodmane Feb 21, 2022
a773e9b
Fix INCLUDE_FULL_LIBRARY test
hoodmane Feb 21, 2022
16f160d
Fix flake8
hoodmane Feb 21, 2022
fbcf6da
Formatting fixes from sbc100
hoodmane Feb 22, 2022
8ad7932
Fix test
hoodmane Feb 22, 2022
68c129e
Return char* instead of returning by value to avoid stackAlloc
hoodmane Feb 22, 2022
c11d036
Remove FORMAT_EXCEPTION_SUPPORT setting
hoodmane Feb 22, 2022
9c0b0a6
Address more review comments
hoodmane Feb 22, 2022
439c09f
Address more review comments
hoodmane Feb 22, 2022
77376ea
Remove unneeded setting
hoodmane Feb 22, 2022
8dad972
Add formatException to EXPORTED_FUNCTIONS rather than EXPORTED_RUNTIM…
hoodmane Feb 22, 2022
dcc15f5
Edits from code review
hoodmane Feb 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2074,6 +2074,11 @@ def default_setting(name, new_default):
else:
settings.JS_LIBRARIES.append((0, 'library_pthread_stub.js'))

# TODO: Move this into the library JS file once it becomes possible.
# See https://github.com/emscripten-core/emscripten/pull/15982
if settings.INCLUDE_FULL_LIBRARY and not settings.DISABLE_EXCEPTION_CATCHING:
settings.EXPORTED_FUNCTIONS += ['_emscripten_format_exception', '_free']

if settings.FORCE_FILESYSTEM and not settings.MINIMAL_RUNTIME:
# when the filesystem is forced, we export by default methods that filesystem usage
# may need, including filesystem usage from standalone file packager output (i.e.
Expand Down
10 changes: 10 additions & 0 deletions src/library_exceptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,16 @@ var LibraryExceptions = {
catchInfo.free();
{{{ makeThrow('ptr') }}}
},

#if !DISABLE_EXCEPTION_CATCHING
$formatException__deps: ['emscripten_format_exception', 'free'],
$formatException: function(excPtr) {
var utf8_addr = _emscripten_format_exception(excPtr);
var result = UTF8ToString(utf8_addr);
_free(utf8_addr);
return result;
},
#endif
};

// In LLVM, exceptions generate a set of functions of form __cxa_find_matching_catch_1(), __cxa_find_matching_catch_2(), etc.
Expand Down
46 changes: 46 additions & 0 deletions system/lib/libcxxabi/src/format_exception.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "cxa_exception.h"
#include "cxxabi.h"
#include <stdio.h>
#include <typeinfo>

#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__

extern "C" {

int __cxa_can_catch(const std::type_info* catchType,
const std::type_info* excpType,
void** thrown);

char* emscripten_format_exception(void* exc_ptr) {
__cxxabiv1::__cxa_exception* exc_info =
(__cxxabiv1::__cxa_exception*)exc_ptr - 1;
std::type_info* exc_type = exc_info->exceptionType;
const char* exc_name = exc_type->name();

int status = 0;
char* demangled_buf = __cxxabiv1::__cxa_demangle(exc_name, 0, 0, &status);
if (status == 0 && demangled_buf) {
exc_name = demangled_buf;
}

int can_catch = __cxa_can_catch(&typeid(std::exception), exc_type, &exc_ptr);
char* result = NULL;
if (can_catch) {
const char* exc_what = ((std::exception*)exc_ptr)->what();
asprintf(&result, "Cpp Exception %s: %s", exc_name, exc_what);
} else {
asprintf(&result,
"Cpp Exception: The exception is an object of type '%s' at "
"address %p which does not inherit from std::exception",
exc_name,
exc_ptr);
}

if (demangled_buf) {
free(demangled_buf);
}
return result;
}
}

#endif // __USING_EMSCRIPTEN_EXCEPTIONS__
55 changes: 55 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,61 @@ def test_exceptions_rethrow_missing(self):
create_file('main.cpp', 'int main() { throw; }')
self.do_runf('main.cpp', None, assert_returncode=NON_ZERO)

def test_format_exception(self):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add @with_both_eh_sjlj to this test?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Then you can also remove DISABLE_EXCEPTION_CATCHING below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't work with wasm-exceptions. I am not sure how to make it work with wasm-exceptions, if you like I can look into it. It would probably be entertaining. But I think it should be a separate PR.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I see, can you open a bug about that so that we remember to get it fixed. I imagine @aheejin will want it to work for sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I opened #16380 which is where I got stuck in the wasm-exceptions case.

self.set_setting('DISABLE_EXCEPTION_CATCHING', 0)
self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$formatException'])
self.set_setting('EXPORTED_FUNCTIONS', ['_main', 'formatException', '_emscripten_format_exception', '_free'])
self.maybe_closure()
src = '''
#include <emscripten.h>
#include <exception>
#include <stdexcept>
using namespace std;

class myexception : public exception {
virtual const char* what() const throw() { return "My exception happened"; }
} myex;

EMSCRIPTEN_KEEPALIVE extern "C" void throw_exc(int x) {
if (x == 1) {
throw 1000;
}
if (x == 2) {
throw 'c';
}
if (x == 3) {
throw runtime_error("abc");
}
if (x == 4) {
throw myex;
}
if (x == 5) {
throw "abc";
}
}

int main() {
EM_ASM({
for (let i = 1; i < 6; i++){
try {
Module["_throw_exc"](i);
} catch(p) {
console.log(Module["formatException"](p).replace(/0x[0-9a-f]*/, "xxx"));
}
}
});
}
'''
expected = '''\
Cpp Exception: The exception is an object of type 'int' at address xxx which does not inherit from std::exception
Cpp Exception: The exception is an object of type 'char' at address xxx which does not inherit from std::exception
Cpp Exception std::runtime_error: abc
Cpp Exception myexception: My exception happened
Cpp Exception: The exception is an object of type 'char const*' at address xxx which does not inherit from std::exception
'''

self.do_run(src, expected)

@with_both_eh_sjlj
def test_bad_typeid(self):
self.do_run(r'''
Expand Down
3 changes: 2 additions & 1 deletion tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,8 @@ def get_files(self):
'stdlib_exception.cpp',
'stdlib_stdexcept.cpp',
'stdlib_typeinfo.cpp',
'private_typeinfo.cpp'
'private_typeinfo.cpp',
'format_exception.cpp',
]
if self.eh_mode == Exceptions.NONE:
filenames += ['cxa_noexception.cpp']
Expand Down