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:
Родитель
fd647d29ac
Коммит
d262c2a6c5
|
@ -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`
|
||||
|
|
7
emcc.py
7
emcc.py
|
@ -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
|
||||
|
|
|
@ -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'''
|
||||
|
|
Загрузка…
Ссылка в новой задаче