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

abort() on malloc() failure in new with exceptions disabled #11079

Merged
merged 10 commits into from
May 5, 2020
Merged
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
9 changes: 9 additions & 0 deletions system/lib/libcxx/new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC
else
#ifndef _LIBCPP_NO_EXCEPTIONS
throw std::bad_alloc();
#else
#ifdef __EMSCRIPTEN__
// Abort here so that when exceptions are disabled, we do not just
// return 0 when malloc returns 0.
// We could also do this with set_new_handler, but that adds a
// global constructor and a table entry, overhead that we can avoid
// by doing it this way.
abort();
#else
break;
#endif
#endif
}
return p;
Expand Down
9 changes: 9 additions & 0 deletions system/lib/libcxxabi/src/stdlib_new_delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC
else
#ifndef _LIBCXXABI_NO_EXCEPTIONS
throw std::bad_alloc();
#else
#ifdef __EMSCRIPTEN__
// Abort here so that when exceptions are disabled, we do not just
// return 0 when malloc returns 0.
// We could also do this with set_new_handler, but that adds a
// global constructor and a table entry, overhead that we can avoid
// by doing it this way.
abort();
#else
break;
#endif
#endif
}
return p;
Expand Down
23 changes: 23 additions & 0 deletions tests/core/test_aborting_new.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <emscripten.h>
#include <stdio.h>
#include <vector>

EMSCRIPTEN_KEEPALIVE extern "C" void allocate_too_much() {
std::vector<int> x;
puts("allocating more than TOTAL_MEMORY; this will fail.");
x.resize(20 * 1024 * 1024);
puts("oh no, it didn't fail!");
}

int main() {
EM_ASM({
// Catch the failure here so we can report it.
try {
_allocate_too_much();
out("no abort happened");
} catch (e) {
assert(("" + e).indexOf("abort") >= 0, "expect an abort from new");
out("new aborted as expected");
}
});
}
1 change: 1 addition & 0 deletions tests/core/test_aborting_new.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
new aborted as expected
10 changes: 10 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2169,6 +2169,16 @@ def test_memorygrowth_3_force_fail_reallocBuffer(self):
self.emcc_args += ['-Wno-almost-asm', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'TEST_MEMORY_GROWTH_FAILS=1']
self.do_run_in_out_file_test('tests', 'core', 'test_memorygrowth_3')

@parameterized({
'nogrow': (['-s', 'ALLOW_MEMORY_GROWTH=0'],),
'grow': (['-s', 'ALLOW_MEMORY_GROWTH=1'],)
})
def test_aborting_new(self, args):
# test that C++ new properly errors if we fail to malloc when growth is
# enabled, with or without growth
self.emcc_args += ['-Wno-almost-asm', '-s', 'MAXIMUM_MEMORY=18MB'] + args
self.do_run_in_out_file_test('tests', 'core', 'test_aborting_new')

@no_asmjs()
@no_wasm2js('no WebAssembly.Memory()')
@no_asan('ASan alters the memory size')
Expand Down