Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,11 @@ if(EMSCRIPTEN)
# Avoid catching exit as that can confuse error reporting in Node,
# see https://github.com/emscripten-core/emscripten/issues/17228
target_link_libraries(binaryen_wasm PRIVATE "-sNODEJS_CATCH_EXIT=0")
# Don't exit the process on a fatal error, instead throw, so that JS can
# catch.
add_compile_flag("-DTHROW_ON_FATAL")
# Add support for printing C++ exceptions from JS.
target_link_libraries(binaryen_wasm PRIVATE "-sEXPORT_EXCEPTION_HANDLING_HELPERS")
install(TARGETS binaryen_wasm DESTINATION ${CMAKE_INSTALL_BINDIR})

# binaryen.js JavaScript variant
Expand Down Expand Up @@ -632,6 +637,8 @@ if(EMSCRIPTEN)
# Avoid catching exit as that can confuse error reporting in Node,
# see https://github.com/emscripten-core/emscripten/issues/17228
target_link_libraries(binaryen_js PRIVATE "-sNODEJS_CATCH_EXIT=0")
add_compile_flag("-DTHROW_ON_FATAL")
target_link_libraries(binaryen_js PRIVATE "-sEXPORT_EXCEPTION_HANDLING_HELPERS")
install(TARGETS binaryen_js DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()

Expand Down
25 changes: 23 additions & 2 deletions src/js/binaryen.js-post.js
Original file line number Diff line number Diff line change
Expand Up @@ -3254,6 +3254,27 @@ Module['emitText'] = function(expr) {
return ret;
};

// Calls a function, wrapping it in error handling code so that if it hits a
// fatal error, we throw a JS exception (which JS can handle) rather than
// abort the entire process (which would not be a friendly behavior for a
// library like binaryen.js).
function handleFatalError(func) {
try {
return func();
} catch (e) {
// C++ exceptions are thrown as pointers (numbers).
if (typeof e === 'number') {
// Fatal errors begin with that prefix. Strip it out, and the newline.
var [_, message] = getExceptionMessage(e);
if (message?.startsWith('Fatal: ')) {
throw new Error(message.substr(7).trim());
}
}
// Rethrow anything else.
throw e;
}
}

// Parses a binary to a module

// If building with Emscripten ASSERTIONS, there is a property added to
Expand All @@ -3264,7 +3285,7 @@ Object.defineProperty(Module, 'readBinary', { writable: true });
Module['readBinary'] = function(data) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a nit but with #8122 I started trying to add some documentation with jsdoc how would we feel about continuing that pattern when possible?

Suggested change
Module['readBinary'] = function(data) {
/**
* Creates a module from binary data.
*
* @param {Uint8Array} data - A Uint8Array containing a valid WebAssembly binary.
*
* @return {Module} The constructed wasm module.
*
* @throws {Error} If the input is invalid or parsing fails.
*/
Module['readBinary'] = function(data) {

Copy link
Member

Choose a reason for hiding this comment

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

Is this to autogenerate some doc? The comment here seems kind of obvious.

Copy link
Member Author

Choose a reason for hiding this comment

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

I assume @spotandjake you are thinking of autogenerating a docs page from the jsdocs comments?

That might be useful, though I'm not sure how much.

const buffer = _malloc(data.length);
HEAP8.set(data, buffer);
const ptr = Module['_BinaryenModuleRead'](buffer, data.length);
const ptr = handleFatalError(() => Module['_BinaryenModuleRead'](buffer, data.length));
_free(buffer);
return wrapModule(ptr);
};
Expand All @@ -3273,7 +3294,7 @@ Module['readBinary'] = function(data) {
Module['parseText'] = function(text) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above:

Suggested change
Module['parseText'] = function(text) {
/**
* Creates a module from Binaryen's s-expression text format (not official stack-style text format).
*
* @param {string} text - A string containing a WebAssembly text module (Binaryen-style WAT).
*
* @return {Module} The constructed wasm module.
*
* @throws {Error} If the input is invalid or parsing fails.
*/
Module['parseText'] = function(text) {

const buffer = _malloc(text.length + 1);
stringToAscii(text, buffer);
const ptr = Module['_BinaryenModuleParse'](buffer);
const ptr = handleFatalError(() => Module['_BinaryenModuleParse'](buffer));
_free(buffer);
return wrapModule(ptr);
};
Expand Down
17 changes: 17 additions & 0 deletions test/binaryen.js/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Parse invalid text and get a JS exception.
var caughtAsExpected = false;
try {
console.log('parsing invalid text...');
binaryen.parseText(`(module
;; error on next line
(func $foo (param__error $x i32))
)`)
console.log('no error - invalid');
} catch (e) {
assert(e.message === '3:16: error: unrecognized instruction');
caughtAsExpected = true;
}
assert(caughtAsExpected);

console.log('success.');

1 change: 1 addition & 0 deletions test/binaryen.js/errors.js.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
success.
Loading