about summary refs log tree commit diff
path: root/src/malloc/lite_malloc.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2015-06-14 01:59:02 +0000
committerRich Felker <dalias@aerifal.cx>2015-06-14 01:59:02 +0000
commite3bc22f1eff87b8f029a6ab31f1a269d69e4b053 (patch)
treed0fc5ca6b5a1a5740f739a37ff5d8c7446fbfd9a /src/malloc/lite_malloc.c
parent4ef9b828c1f39553a69e0635ac91f0fcadd6e8c6 (diff)
downloadmusl-e3bc22f1eff87b8f029a6ab31f1a269d69e4b053.tar.gz
musl-e3bc22f1eff87b8f029a6ab31f1a269d69e4b053.tar.xz
musl-e3bc22f1eff87b8f029a6ab31f1a269d69e4b053.zip
refactor malloc's expand_heap to share with __simple_malloc
this extends the brk/stack collision protection added to full malloc
in commit 276904c2f6bde3a31a24ebfa201482601d18b4f9 to also protect the
__simple_malloc function used in static-linked programs that don't
reference the free function.

it also extends support for using mmap when brk fails, which full
malloc got in commit 5446303328adf4b4e36d9fba21848e6feb55fab4, to
__simple_malloc.

since __simple_malloc may expand the heap by arbitrarily large
increments, the stack collision detection is enhanced to detect
interval overlap rather than just proximity of a single address to the
stack. code size is increased a bit, but this is partly offset by the
sharing of code between the two malloc implementations, which due to
linking semantics, both get linked in a program that needs the full
malloc with realloc/free support.
Diffstat (limited to 'src/malloc/lite_malloc.c')
-rw-r--r--src/malloc/lite_malloc.c49
1 files changed, 26 insertions, 23 deletions
diff --git a/src/malloc/lite_malloc.c b/src/malloc/lite_malloc.c
index 7643fc2c..008549d6 100644
--- a/src/malloc/lite_malloc.c
+++ b/src/malloc/lite_malloc.c
@@ -4,43 +4,46 @@
 #include <errno.h>
 #include "libc.h"
 
-uintptr_t __brk(uintptr_t);
-
 #define ALIGN 16
 
+void *__expand_heap(size_t *);
+
 void *__simple_malloc(size_t n)
 {
-	static uintptr_t cur, brk;
-	uintptr_t base, new;
+	static char *cur, *end;
 	static volatile int lock[2];
-	size_t align=1;
+	size_t align=1, pad;
+	void *p;
 
 	if (!n) n++;
-	if (n > SIZE_MAX/2) goto toobig;
-
 	while (align<n && align<ALIGN)
 		align += align;
-	n = n + align - 1 & -align;
 
 	LOCK(lock);
-	if (!cur) cur = brk = __brk(0)+16;
-	base = cur + align-1 & -align;
-	if (n > SIZE_MAX - PAGE_SIZE - base) goto fail;
-	if (base+n > brk) {
-		new = base+n + PAGE_SIZE-1 & -PAGE_SIZE;
-		if (__brk(new) != new) goto fail;
-		brk = new;
-	}
-	cur = base+n;
-	UNLOCK(lock);
 
-	return (void *)base;
+	pad = -(uintptr_t)cur & align-1;
+
+	if (n <= SIZE_MAX/2 + ALIGN) n += pad;
+
+	if (n > end-cur) {
+		size_t m = n;
+		char *new = __expand_heap(&m);
+		if (!new) {
+			UNLOCK(lock);
+			return 0;
+		}
+		if (new != end) {
+			cur = new;
+			n -= pad;
+			pad = 0;
+		}
+		end = new + m;
+	}
 
-fail:
+	p = cur + pad;
+	cur += n;
 	UNLOCK(lock);
-toobig:
-	errno = ENOMEM;
-	return 0;
+	return p;
 }
 
 weak_alias(__simple_malloc, malloc);