Skip to content

Commit 5ccfbac

Browse files
authored
Proper error handling in add* and get* methods (#1570)
See #1479 (comment) Also a one-line readme update, remove an obsolete compiler (mir2wasm) and add a new one (asterius). Also improve warning and error reporting in binaryen.js - show a stack trace when relevant (instead of node.js process.exit), and avoid atexit warning spam in debug builds.
1 parent 14ea999 commit 5ccfbac

File tree

9 files changed

+116
-38
lines changed

9 files changed

+116
-38
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Compilers built using Binaryen include
1313
* [`asm2wasm`](https://github.com/WebAssembly/binaryen/blob/master/src/asm2wasm.h) which compiles asm.js to WebAssembly
1414
* [`AssemblyScript`](https://github.com/AssemblyScript/assemblyscript) which compiles TypeScript to Binaryen IR
1515
* [`wasm2asm`](https://github.com/WebAssembly/binaryen/blob/master/src/wasm2asm.h) which compiles WebAssembly to asm.js
16-
* [`mir2wasm`](https://github.com/brson/mir2wasm/) which compiles Rust MIR
16+
* [`Asterius`](https://github.com/tweag/asterius) which compiles Haskell to WebAssembly
1717

1818
Binaryen also provides a set of **toolchain utilities** that can
1919

auto_update_tests.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,11 @@ def update_binaryen_js_tests():
313313
f.close()
314314
if MOZJS or node_has_wasm or 'WebAssembly.' not in test_src:
315315
cmd = [MOZJS or NODEJS, 'a.js']
316-
out = run_command(cmd, stderr=subprocess.STDOUT)
316+
if 'fatal' not in s:
317+
out = run_command(cmd, stderr=subprocess.STDOUT)
318+
else:
319+
# expect an error - the specific error code will depend on the vm
320+
out = run_command(cmd, stderr=subprocess.STDOUT, expected_status=None)
317321
with open(os.path.join('test', 'binaryen.js', s + '.txt'), 'w') as o:
318322
o.write(out)
319323
else:

check.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,11 @@ def run_binaryen_js_tests():
436436

437437
def test(engine):
438438
cmd = [engine, 'a.js']
439-
out = run_command(cmd, stderr=subprocess.STDOUT)
439+
if 'fatal' not in s:
440+
out = run_command(cmd, stderr=subprocess.STDOUT)
441+
else:
442+
# expect an error - the specific error code will depend on the vm
443+
out = run_command(cmd, stderr=subprocess.STDOUT, expected_status=None)
440444
expected = open(os.path.join(options.binaryen_test, 'binaryen.js', s + '.txt')).read()
441445
if expected not in out:
442446
fail(out, expected)
@@ -510,7 +514,7 @@ def run_vanilla_tests():
510514
del os.environ['EMCC_WASM_BACKEND']
511515

512516

513-
def run_gcc_torture_tests():
517+
def run_gcc_tests():
514518
print '\n[ checking native gcc testcases...]\n'
515519
if not NATIVECC or not NATIVEXX:
516520
fail_with_error('Native compiler (e.g. gcc/g++) was not found in PATH!')
@@ -648,7 +652,7 @@ def main():
648652
run_vanilla_tests()
649653
print '\n[ checking example testcases... ]\n'
650654
if options.run_gcc_tests:
651-
run_gcc_torture_tests()
655+
run_gcc_tests()
652656
if EMCC:
653657
run_emscripten_tests()
654658

scripts/test/support.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def run_command(cmd, expected_status=0, stderr=None,
156156
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=stderr, universal_newlines=True)
157157
out, err = proc.communicate()
158158
code = proc.returncode
159-
if code != expected_status:
159+
if expected_status is not None and code != expected_status:
160160
raise Exception(('run_command failed (%s)' % code, out + str(err or '')))
161161
err_correct = expected_err is None or \
162162
(expected_err in err if err_contains else expected_err == err)

src/binaryen-c.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,4 +2601,12 @@ BinaryenFunctionTypeRef BinaryenGetFunctionTypeBySignature(BinaryenModuleRef mod
26012601
return NULL;
26022602
}
26032603

2604+
#ifdef __EMSCRIPTEN__
2605+
// Override atexit - we don't need any global ctors to actually run, and
2606+
// otherwise we get clutter in the output in debug builds
2607+
int atexit(void (*function)(void)) {
2608+
return 0;
2609+
}
2610+
#endif
2611+
26042612
} // extern "C"

src/js/binaryen.js-post.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,3 +1609,12 @@ Module['setDebugInfo'] = function(on) {
16091609
Module['setAPITracing'] = function(on) {
16101610
return Module['_BinaryenSetAPITracing'](on);
16111611
};
1612+
1613+
// Additional customizations
1614+
1615+
Module['exit'] = function(status) {
1616+
// Instead of exiting silently on errors, always show an error with
1617+
// a stack trace, for debuggability.
1618+
if (status != 0) throw new Error('exiting due to error: ' + status);
1619+
};
1620+

src/wasm/wasm.cpp

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,11 @@ Name Function::getLocalNameOrGeneric(Index index) {
619619
}
620620

621621
Index Function::getLocalIndex(Name name) {
622-
assert(localIndices.count(name) > 0);
623-
return localIndices[name];
622+
auto iter = localIndices.find(name);
623+
if (iter == localIndices.end()) {
624+
Fatal() << "Function::getLocalIndex: " << name << " does not exist";
625+
}
626+
return iter->second;
624627
}
625628

626629
Index Function::getVarIndexBase() {
@@ -638,92 +641,137 @@ Type Function::getLocalType(Index index) {
638641
}
639642

640643
FunctionType* Module::getFunctionType(Name name) {
641-
assert(functionTypesMap.count(name));
642-
return functionTypesMap[name];
644+
auto iter = functionTypesMap.find(name);
645+
if (iter == functionTypesMap.end()) {
646+
Fatal() << "Module::getFunctionType: " << name << " does not exist";
647+
}
648+
return iter->second;
643649
}
644650

645651
Import* Module::getImport(Name name) {
646-
assert(importsMap.count(name));
647-
return importsMap[name];
652+
auto iter = importsMap.find(name);
653+
if (iter == importsMap.end()) {
654+
Fatal() << "Module::getImport: " << name << " does not exist";
655+
}
656+
return iter->second;
648657
}
649658

650659
Export* Module::getExport(Name name) {
651-
assert(exportsMap.count(name));
652-
return exportsMap[name];
660+
auto iter = exportsMap.find(name);
661+
if (iter == exportsMap.end()) {
662+
Fatal() << "Module::getExport: " << name << " does not exist";
663+
}
664+
return iter->second;
653665
}
654666

655667
Function* Module::getFunction(Name name) {
656-
assert(functionsMap.count(name));
657-
return functionsMap[name];
668+
auto iter = functionsMap.find(name);
669+
if (iter == functionsMap.end()) {
670+
Fatal() << "Module::getFunction: " << name << " does not exist";
671+
}
672+
return iter->second;
658673
}
659674

660675
Global* Module::getGlobal(Name name) {
661-
assert(globalsMap.count(name));
662-
return globalsMap[name];
676+
auto iter = globalsMap.find(name);
677+
if (iter == globalsMap.end()) {
678+
Fatal() << "Module::getGlobal: " << name << " does not exist";
679+
}
680+
return iter->second;
663681
}
664682

665683
FunctionType* Module::getFunctionTypeOrNull(Name name) {
666-
if (!functionTypesMap.count(name))
684+
auto iter = functionTypesMap.find(name);
685+
if (iter == functionTypesMap.end()) {
667686
return nullptr;
668-
return functionTypesMap[name];
687+
}
688+
return iter->second;
669689
}
670690

671691
Import* Module::getImportOrNull(Name name) {
672-
if (!importsMap.count(name))
692+
auto iter = importsMap.find(name);
693+
if (iter == importsMap.end()) {
673694
return nullptr;
674-
return importsMap[name];
695+
}
696+
return iter->second;
675697
}
676698

677699
Export* Module::getExportOrNull(Name name) {
678-
if (!exportsMap.count(name))
700+
auto iter = exportsMap.find(name);
701+
if (iter == exportsMap.end()) {
679702
return nullptr;
680-
return exportsMap[name];
703+
}
704+
return iter->second;
681705
}
682706

683707
Function* Module::getFunctionOrNull(Name name) {
684-
if (!functionsMap.count(name))
708+
auto iter = functionsMap.find(name);
709+
if (iter == functionsMap.end()) {
685710
return nullptr;
686-
return functionsMap[name];
711+
}
712+
return iter->second;
687713
}
688714

689715
Global* Module::getGlobalOrNull(Name name) {
690-
if (!globalsMap.count(name))
716+
auto iter = globalsMap.find(name);
717+
if (iter == globalsMap.end()) {
691718
return nullptr;
692-
return globalsMap[name];
719+
}
720+
return iter->second;
693721
}
694722

695723
void Module::addFunctionType(FunctionType* curr) {
696-
assert(curr->name.is());
724+
if (!curr->name.is()) {
725+
Fatal() << "Module::addFunctionType: empty name";
726+
}
727+
if (getFunctionTypeOrNull(curr->name)) {
728+
Fatal() << "Module::addFunctionType: " << curr->name << " already exists";
729+
}
697730
functionTypes.push_back(std::unique_ptr<FunctionType>(curr));
698-
assert(functionTypesMap.find(curr->name) == functionTypesMap.end());
699731
functionTypesMap[curr->name] = curr;
700732
}
701733

702734
void Module::addImport(Import* curr) {
703-
assert(curr->name.is());
735+
if (!curr->name.is()) {
736+
Fatal() << "Module::addImport: empty name";
737+
}
738+
if (getImportOrNull(curr->name)) {
739+
Fatal() << "Module::addImport: " << curr->name << " already exists";
740+
}
704741
imports.push_back(std::unique_ptr<Import>(curr));
705-
assert(importsMap.find(curr->name) == importsMap.end());
706742
importsMap[curr->name] = curr;
707743
}
708744

709745
void Module::addExport(Export* curr) {
710-
assert(curr->name.is());
746+
if (!curr->name.is()) {
747+
Fatal() << "Module::addExport: empty name";
748+
}
749+
if (getExportOrNull(curr->name)) {
750+
Fatal() << "Module::addExport: " << curr->name << " already exists";
751+
}
711752
exports.push_back(std::unique_ptr<Export>(curr));
712-
assert(exportsMap.find(curr->name) == exportsMap.end());
713753
exportsMap[curr->name] = curr;
714754
}
715755

716756
void Module::addFunction(Function* curr) {
717-
assert(curr->name.is());
757+
if (!curr->name.is()) {
758+
Fatal() << "Module::addFunction: empty name";
759+
}
760+
if (getFunctionOrNull(curr->name)) {
761+
Fatal() << "Module::addFunction: " << curr->name << " already exists";
762+
}
718763
functions.push_back(std::unique_ptr<Function>(curr));
719-
assert(functionsMap.find(curr->name) == functionsMap.end());
720764
functionsMap[curr->name] = curr;
721765
}
722766

723767
void Module::addGlobal(Global* curr) {
724-
assert(curr->name.is());
768+
if (!curr->name.is()) {
769+
Fatal() << "Module::addGlobal: empty name";
770+
}
771+
if (getGlobalOrNull(curr->name)) {
772+
Fatal() << "Module::addGlobal: " << curr->name << " already exists";
773+
}
725774
globals.push_back(std::unique_ptr<Global>(curr));
726-
assert(globalsMap.find(curr->name) == globalsMap.end());
727775
globalsMap[curr->name] = curr;
728776
}
729777

test/binaryen.js/fatal.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
var wasm = new Binaryen.Module()
2+
wasm.addFunctionType("vI", Binaryen.i32, []);
3+
// It will cause a fatal error to try to add the same name a second time
4+
wasm.addFunctionType("vI", Binaryen.i32, []);

test/binaryen.js/fatal.js.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fatal: Module::addFunctionType: $vI already exists

0 commit comments

Comments
 (0)