Skip to content

Commit f2aac5f

Browse files
authored
Don't use sbrk(0) to determine the initial heap size (#377)
* Don't use sbrk(0) to determine the initial heap size This commit changes the `try_init_allocator` function as part of dlmalloc to not use `sbrk(0)` to determine the initial heap size. The purpose of this function is to use the extra memory at the end of linear memory for the initial allocation heap before `memory.grow` is used to allocate more memory. To learn the extent of this region the code previously would use `sbrk(0)` to find the current size of linear memory. This does not work, however, when other systems have called `memory.grow` before this function is called. For example if another allocator is used or if another component of a wasm binary grows memory for its own purposes then that memory will be incorrectly claimed to be owned by dlmalloc. Instead this commit rounds up the `__heap_base` address to the nearest page size, since that must be allocatable. Otherwise anything above this rounded address is assumed to be used by something else, even if it's addressable. * Use `__heap_end` if defined * Move mstate initialization earlier
1 parent 5a255d5 commit f2aac5f

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

dlmalloc/src/malloc.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5214,26 +5214,43 @@ static void internal_inspect_all(mstate m,
52145214
/* ------------------ Exported try_init_allocator -------------------- */
52155215

52165216
/* Symbol marking the end of data, bss and explicit stack, provided by wasm-ld. */
5217-
extern unsigned char __heap_base;
5217+
extern char __heap_base;
5218+
extern char __heap_end __attribute__((__weak__));
52185219

52195220
/* Initialize the initial state of dlmalloc to be able to use free memory between __heap_base and initial. */
52205221
static void try_init_allocator(void) {
52215222
/* Check that it is a first-time initialization. */
52225223
assert(!is_initialized(gm));
52235224

5224-
char *base = (char *)&__heap_base;
5225-
/* Calls sbrk(0) that returns the initial memory position. */
5226-
char *init = (char *)CALL_MORECORE(0);
5227-
int initial_heap_size = init - base;
5225+
/* Initialize mstate. */
5226+
ensure_initialization();
5227+
5228+
char *base = &__heap_base;
5229+
// Try to use the linker pseudo-symbol `__heap_end` for the initial size of
5230+
// the heap, but if that's not defined due to LLVM being too old perhaps then
5231+
// round up `base` to the nearest `PAGESIZE`. The initial size of linear
5232+
// memory will be at least the heap base to this page boundary, and it's then
5233+
// assumed that the initial linear memory image was truncated at that point.
5234+
// While this reflects the default behavior of `wasm-ld` it is also possible
5235+
// for users to craft larger linear memories by passing options to extend
5236+
// beyond this threshold. In this situation the memory will not be used for
5237+
// dlmalloc.
5238+
//
5239+
// Note that `sbrk(0)`, or in dlmalloc-ese `CALL_MORECORE(0)`, is specifically
5240+
// not used here. That captures the current size of the heap but is only
5241+
// correct if the we're the first to try to grow the heap. If the heap has
5242+
// grown elsewhere, such as a different allocator in place, then this would
5243+
// incorrectly claim such memroy as our own.
5244+
char *end = &__heap_end;
5245+
if (end == NULL)
5246+
end = (char*) page_align((size_t) base);
5247+
size_t initial_heap_size = end - base;
52285248

52295249
/* Check that initial heap is long enough to serve a minimal allocation request. */
52305250
if (initial_heap_size <= MIN_CHUNK_SIZE + TOP_FOOT_SIZE + MALLOC_ALIGNMENT) {
52315251
return;
52325252
}
52335253

5234-
/* Initialize mstate. */
5235-
ensure_initialization();
5236-
52375254
/* Initialize the dlmalloc internal state. */
52385255
gm->least_addr = base;
52395256
gm->seg.base = base;

0 commit comments

Comments
 (0)