Make ALLOW_MEMORY_GROWTH turn off ABORTING_MALLOC by default, but allow user override (#11131)

ALLOW_MEMORY_GROWTH used to silently disable ABORTING_MALLOC. It now
just changes the default, which means you can pass -s ABORTING_MALLOC=1 to
override the default, which was not possible before. (If you pass the flag
and don't want that behavior, this would be a breaking change, and the solution is
to stop passing the flag.)
This commit is contained in:
Alon Zakai 2020-05-12 10:44:46 -07:00 коммит произвёл GitHub
Родитель fd647d29ac
Коммит d262c2a6c5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 59 добавлений и 18 удалений

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

@ -17,6 +17,10 @@ See docs/process.md for how version tagging works.
Current Trunk
-------------
- `ALLOW_MEMORY_GROWTH` used to silently disable `ABORTING_MALLOC`. It now
just changes the default, which means you can pass `-s ABORTING_MALLOC=1` to
override the default, which was not possible before. (If you pass the flag
and don't want that behavior, stop passing the flag.) (#11131)
- Change the factory function created by using the `MODULARIZE` build option to
return a Promise instead of the module instance. If you use `MODULARIZE` you
will need to wait on the returned Promise, using `await` or its `then`

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

@ -1530,6 +1530,13 @@ There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR P
if not shared.Settings.DECLARE_ASM_MODULE_EXPORTS:
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$exportAsmFunctions']
if shared.Settings.ALLOW_MEMORY_GROWTH and 'ABORTING_MALLOC=1' not in settings_changes:
# Setting ALLOW_MEMORY_GROWTH turns off ABORTING_MALLOC, as in that mode we default to
# the behavior of trying to grow and returning 0 from malloc on failure, like
# a standard system would. However, if the user sets the flag it
# overrides that.
shared.Settings.ABORTING_MALLOC = 0
if shared.Settings.USE_PTHREADS:
if shared.Settings.USE_PTHREADS == 2:
exit_with_error('USE_PTHREADS=2 is not longer supported')

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

@ -459,19 +459,19 @@ LibraryManager.library = {
return {{{ DYNAMICTOP_PTR }}};
},
#if ABORTING_MALLOC && !ALLOW_MEMORY_GROWTH
#if ABORTING_MALLOC
$abortOnCannotGrowMemory: function(requestedSize) {
#if ASSERTIONS
#if WASM
#if ALLOW_MEMORY_GROWTH
abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). If you want malloc to return NULL (0) instead of this abort, do not link with -s ABORTING_MALLOC=1 (that is, the default when growth is enabled is to not abort, but you have overridden that)');
#else // ALLOW_MEMORY_GROWTH
abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value ' + HEAP8.length + ', (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ');
#else
abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value ' + HEAP8.length + ', (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.INITIAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ');
#endif
#else
#endif // ALLOW_MEMORY_GROWTH
#else // ASSERTIONS
abort('OOM');
#endif
#endif // ASSERTIONS
},
#endif
#endif // ABORTING_MALLOC
#if TEST_MEMORY_GROWTH_FAILS
$emscripten_realloc_buffer: function(size) {
@ -515,7 +515,7 @@ LibraryManager.library = {
#if ASSERTIONS == 2
, 'emscripten_get_now'
#endif
#if ABORTING_MALLOC && !ALLOW_MEMORY_GROWTH
#if ABORTING_MALLOC
, '$abortOnCannotGrowMemory'
#endif
#if ALLOW_MEMORY_GROWTH
@ -571,7 +571,11 @@ LibraryManager.library = {
#if ASSERTIONS
err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + maxHeapSize + ' bytes!');
#endif
#if ABORTING_MALLOC
abortOnCannotGrowMemory(requestedSize);
#else
return false;
#endif
}
#if USE_ASAN
// One byte of ASan's shadow memory shadows 8 bytes of real memory. Shadow memory area has a fixed size,
@ -581,7 +585,11 @@ LibraryManager.library = {
#if ASSERTIONS
err('Failed to grow the heap from ' + oldSize + ', as we reached the limit of our shadow memory. Increase ASAN_SHADOW_SIZE.');
#endif
#if ABORTING_MALLOC
abortOnCannotGrowMemory(requestedSize);
#else
return false;
#endif
}
#endif
@ -627,7 +635,11 @@ LibraryManager.library = {
#if ASSERTIONS
err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!');
#endif
#if ABORTING_MALLOC
abortOnCannotGrowMemory(requestedSize);
#else
return false;
#endif
#endif // ALLOW_MEMORY_GROWTH
},

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

@ -132,6 +132,19 @@ var MALLOC = "dlmalloc";
// how big that initial allocation (INITIAL_MEMORY) must be.
// If you set this to 0, then you get the standard malloc behavior of
// returning NULL (0) when it fails.
//
// Setting ALLOW_MEMORY_GROWTH turns this off, as in that mode we default to
// the behavior of trying to grow and returning 0 from malloc on failure, like
// a standard system would. However, you can still set this flag to override
// that.
// * This is a mostly-backwards-compatible change. Previously this option
// was ignored when growth was on. The current behavior is that growth
// turns it off by default, so for users that never specified the flag
// nothing changes. But if you do specify it, it will have an effect now,
// which it did not previously. If you don't want that, just stop passing
// it in at link time.
//
// [link]
var ABORTING_MALLOC = 1;
// If 1, generated a version of memcpy() and memset() that unroll their

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

@ -6183,7 +6183,7 @@ int main() {
('EM_ASM( Module.temp = HEAP32[DYNAMICTOP_PTR>>2] );', 'EM_ASM( assert(Module.temp === HEAP32[DYNAMICTOP_PTR>>2], "must not adjust DYNAMICTOP when an alloc fails!") );', ['-s', 'WASM=0']),
]:
for growth in [0, 1]:
for aborting in [0, 1]:
for aborting_args in [[], ['-s', 'ABORTING_MALLOC=0'], ['-s', 'ABORTING_MALLOC=1']]:
create_test_file('main.cpp', r'''
#include <stdio.h>
#include <stdlib.h>
@ -6224,18 +6224,18 @@ int main() {
printf("managed another malloc!\n");
}
''' % (pre_fail, post_fail))
args = [PYTHON, EMCC, 'main.cpp'] + opts
args = [PYTHON, EMCC, 'main.cpp'] + opts + aborting_args
args += ['-s', 'TEST_MEMORY_GROWTH_FAILS=1'] # In this test, force memory growing to fail
if growth:
args += ['-s', 'ALLOW_MEMORY_GROWTH=1']
if not aborting:
args += ['-s', 'ABORTING_MALLOC=0']
# growth disables aborting by default, but it can be overridden
aborting = 'ABORTING_MALLOC=1' in aborting_args or (not aborting_args and not growth)
print('test_failing_alloc', args, pre_fail)
run_process(args)
# growth also disables aborting
can_manage_another = (not aborting) or growth
can_manage_another = not aborting
split = '-DSPLIT' in args
print('can manage another:', can_manage_another, 'split:', split)
print('can manage another:', can_manage_another, 'split:', split, 'aborting:', aborting)
output = run_js('a.out.js', stderr=PIPE, full_output=True, assert_returncode=0 if can_manage_another else None)
if can_manage_another:
self.assertContained('an allocation failed!\n', output)
@ -6248,9 +6248,14 @@ int main() {
else:
# we should see an abort
self.assertContained('abort(Cannot enlarge memory arrays', output)
self.assertContained(('higher than the current value 16777216,', 'higher than the current value 33554432,'), output)
self.assertContained('compile with -s ALLOW_MEMORY_GROWTH=1 ', output)
self.assertContained('compile with -s ABORTING_MALLOC=0 ', output)
if growth:
# when growth is enabled, the default is to not abort, so just explain that
self.assertContained('If you want malloc to return NULL (0) instead of this abort, do not link with -s ABORTING_MALLOC=1', output)
else:
# when growth is not enabled, suggest 3 possible solutions (start with more memory, allow growth, or don't abort)
self.assertContained(('higher than the current value 16777216,', 'higher than the current value 33554432,'), output)
self.assertContained('compile with -s ALLOW_MEMORY_GROWTH=1 ', output)
self.assertContained('compile with -s ABORTING_MALLOC=0 ', output)
def test_failing_growth_2gb(self):
create_test_file('test.cpp', r'''