Skip to content

Commit 00daf40

Browse files
authored
Fix dlmalloc for allocations bigger than 2GB (#18055)
To do this, add an UNSIGNED_MORECORE option. Wasm cannot shrink memory and so we can treat sbrk's argument as unsigned, which allows allocations of any size up to 4GB in wasm32. Fixes #17747
1 parent de39ea2 commit 00daf40

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

system/lib/dlmalloc.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#define DLMALLOC_EXPORT static
77
/* mmap uses malloc, so malloc can't use mmap */
88
#define HAVE_MMAP 0
9+
/* Emscripten's sbrk can interpret unsigned values greater than (MAX_SIZE_T / 2U) (2GB) correctly */
10+
#define UNSIGNED_MORECORE 1
911
/* we can only grow the heap up anyhow, so don't try to trim */
1012
#define MORECORE_CANNOT_TRIM 1
1113
#ifndef DLMALLOC_DEBUG
@@ -415,6 +417,10 @@ _Static_assert(MALLOC_ALIGNMENT == 8, "max_align_t must be 8");
415417
Setting it false when definitely non-contiguous saves time
416418
and possibly wasted space it would take to discover this though.
417419
420+
UNSIGNED_MORECORE default: 0 (false)
421+
True if MORECORE can only handle unsigned arguments. This sets
422+
MORECORE_CANNOT_TRIM to 1 (true).
423+
418424
MORECORE_CANNOT_TRIM default: NOT defined
419425
True if MORECORE cannot release space back to the system when given
420426
negative arguments. This is generally necessary only if you are
@@ -713,6 +719,12 @@ defined(__i386__) || defined(__x86_64__))) || \
713719
#define HAVE_MORECORE 1
714720
#endif /* ONLY_MSPACES */
715721
#endif /* HAVE_MORECORE */
722+
#ifndef UNSIGNED_MORECORE
723+
#define UNSIGNED_MORECORE 0
724+
#endif /* UNSIGNED_MORECORE */
725+
#if UNSIGNED_MORECORE
726+
#define MORECORE_CANNOT_TRIM 1
727+
#endif /* UNSIGNED_MORECORE */
716728
#if !HAVE_MORECORE
717729
#define MORECORE_CONTIGUOUS 0
718730
#else /* !HAVE_MORECORE */
@@ -4161,7 +4173,8 @@ static void* sys_alloc(mstate m, size_t nb) {
41614173
if (!is_page_aligned(base))
41624174
ssize += (page_align((size_t)base) - (size_t)base);
41634175
fp = m->footprint + ssize; /* recheck limits */
4164-
if (ssize > nb && ssize < HALF_MAX_SIZE_T &&
4176+
if (ssize > nb &&
4177+
(UNSIGNED_MORECORE || ssize < HALF_MAX_SIZE_T) &&
41654178
(m->footprint_limit == 0 ||
41664179
(fp > m->footprint && fp <= m->footprint_limit)) &&
41674180
(br = (char*)(CALL_MORECORE(ssize))) == base) {
@@ -4174,7 +4187,7 @@ static void* sys_alloc(mstate m, size_t nb) {
41744187
/* Subtract out existing available top space from MORECORE request. */
41754188
ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
41764189
/* Use mem here only if it did continuously extend old space */
4177-
if (ssize < HALF_MAX_SIZE_T &&
4190+
if ((UNSIGNED_MORECORE || ssize < HALF_MAX_SIZE_T) &&
41784191
(br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) {
41794192
tbase = br;
41804193
tsize = ssize;
@@ -4183,15 +4196,17 @@ static void* sys_alloc(mstate m, size_t nb) {
41834196

41844197
if (tbase == CMFAIL) { /* Cope with partial failure */
41854198
if (br != CMFAIL) { /* Try to use/extend the space we did get */
4186-
if (ssize < HALF_MAX_SIZE_T &&
4199+
if ((UNSIGNED_MORECORE || ssize < HALF_MAX_SIZE_T) &&
41874200
ssize < nb + SYS_ALLOC_PADDING) {
41884201
size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize);
4189-
if (esize < HALF_MAX_SIZE_T) {
4202+
if (UNSIGNED_MORECORE || esize < HALF_MAX_SIZE_T) {
41904203
char* end = (char*)CALL_MORECORE(esize);
41914204
if (end != CMFAIL)
41924205
ssize += esize;
41934206
else { /* Can't use; try to release */
4194-
(void) CALL_MORECORE(-ssize);
4207+
if (!UNSIGNED_MORECORE) {
4208+
(void) CALL_MORECORE(-ssize);
4209+
}
41954210
br = CMFAIL;
41964211
}
41974212
}
@@ -4218,7 +4233,7 @@ static void* sys_alloc(mstate m, size_t nb) {
42184233
}
42194234

42204235
if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
4221-
if (asize < HALF_MAX_SIZE_T) {
4236+
if (UNSIGNED_MORECORE || asize < HALF_MAX_SIZE_T) {
42224237
char* br = CMFAIL;
42234238
char* end = CMFAIL;
42244239
ACQUIRE_MALLOC_GLOBAL_LOCK();
@@ -4387,6 +4402,7 @@ static int sys_trim(mstate m, size_t pad) {
43874402
}
43884403
}
43894404
else if (HAVE_MORECORE) {
4405+
#ifndef MORECORE_CANNOT_TRIM
43904406
if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
43914407
extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
43924408
ACQUIRE_MALLOC_GLOBAL_LOCK();
@@ -4401,6 +4417,7 @@ static int sys_trim(mstate m, size_t pad) {
44014417
}
44024418
}
44034419
RELEASE_MALLOC_GLOBAL_LOCK();
4420+
#endif
44044421
}
44054422
}
44064423

@@ -6087,8 +6104,8 @@ extern __typeof(memalign) emscripten_builtin_memalign __attribute__((alias("dlme
60876104
just return MFAIL when given negative arguments.
60886105
Negative arguments are always multiples of pagesize. MORECORE
60896106
must not misinterpret negative args as large positive unsigned
6090-
args. You can suppress all such calls from even occurring by defining
6091-
MORECORE_CANNOT_TRIM,
6107+
args unless UNSIGNED_MORECORE is defined. You can suppress all such calls
6108+
from even occurring by defining MORECORE_CANNOT_TRIM,
60926109
60936110
As an example alternative MORECORE, here is a custom allocator
60946111
kindly contributed for pre-OSX macOS. It uses virtually but not

test/test_browser.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5313,6 +5313,12 @@ def test(args):
53135313
test(['-sMALLOC=emmalloc-memvalidate'])
53145314
test(['-sMALLOC=emmalloc-memvalidate-verbose'])
53155315

5316+
# Test that it is possible to malloc() a huge 3GB memory block in 4GB mode using dlmalloc.
5317+
@no_firefox('no 4GB support yet')
5318+
def test_dlmalloc_3GB(self):
5319+
self.btest_exit(test_file('alloc_3gb.cpp'),
5320+
args=['-sMALLOC=dlmalloc', '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH=1'])
5321+
53165322
@parameterized({
53175323
# the fetch backend works even on the main thread: we proxy to a background
53185324
# thread and busy-wait

0 commit comments

Comments
 (0)