From 642b5fb0007b64c77d186fcb018d571152ee1d47 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Mon, 14 Aug 2023 18:51:07 +0200
Subject: reorganization: first steps

---
 src/user/lib/_start.s                   |   17 -
 src/user/lib/_start2.c                  |   42 -
 src/user/lib/assert.c                   |    8 -
 src/user/lib/camellia.c                 |   30 -
 src/user/lib/compat.c                   |   20 -
 src/user/lib/ctype.c                    |   65 -
 src/user/lib/dirent.c                   |   55 -
 src/user/lib/draw/draw.c                |   83 -
 src/user/lib/draw/flush.c               |   43 -
 src/user/lib/elf.h                      |  188 -
 src/user/lib/elfload.S                  |   20 -
 src/user/lib/elfload.c                  |  182 -
 src/user/lib/elfreloc.c                 |   39 -
 src/user/lib/err.c                      |   50 -
 src/user/lib/esemaphore.c               |   56 -
 src/user/lib/fcntl.c                    |   28 -
 src/user/lib/fs/dir.c                   |   84 -
 src/user/lib/fs/dirinject.c             |  129 -
 src/user/lib/fs/misc.c                  |  160 -
 src/user/lib/fs/whitelist.c             |  114 -
 src/user/lib/include/__errno.h          |   26 -
 src/user/lib/include/__errno.h.awk      |   20 -
 src/user/lib/include/_proc.h            |   14 -
 src/user/lib/include/alloca.h           |    3 -
 src/user/lib/include/bits/file.h        |    2 -
 src/user/lib/include/bits/panic.h       |    5 -
 src/user/lib/include/camellia.h         |    5 -
 src/user/lib/include/camellia/compat.h  |    6 -
 src/user/lib/include/camellia/fs/dir.h  |   17 -
 src/user/lib/include/camellia/fs/misc.h |   22 -
 src/user/lib/include/ctype.h            |   16 -
 src/user/lib/include/dirent.h           |   16 -
 src/user/lib/include/draw.h             |   24 -
 src/user/lib/include/elfload.h          |   14 -
 src/user/lib/include/err.h              |   10 -
 src/user/lib/include/errno.h            |    3 -
 src/user/lib/include/esemaphore.h       |   12 -
 src/user/lib/include/fcntl.h            |   25 -
 src/user/lib/include/ftw.h              |    6 -
 src/user/lib/include/getopt.h           |    1 -
 src/user/lib/include/grp.h              |   11 -
 src/user/lib/include/inttypes.h         |    1 -
 src/user/lib/include/limits.h           |    6 -
 src/user/lib/include/locale.h           |   73 -
 src/user/lib/include/malloc.h           |    1 -
 src/user/lib/include/math.h             |   27 -
 src/user/lib/include/pwd.h              |   14 -
 src/user/lib/include/setjmp.h           |   18 -
 src/user/lib/include/signal.h           |   54 -
 src/user/lib/include/stdio.h            |   84 -
 src/user/lib/include/stdlib.h           |   34 -
 src/user/lib/include/string.h           |   25 -
 src/user/lib/include/strings.h          |    5 -
 src/user/lib/include/sys/ioctl.h        |   13 -
 src/user/lib/include/sys/mman.h         |   18 -
 src/user/lib/include/sys/param.h        |    2 -
 src/user/lib/include/sys/resource.h     |    2 -
 src/user/lib/include/sys/stat.h         |   70 -
 src/user/lib/include/sys/sysmacros.h    |    3 -
 src/user/lib/include/sys/time.h         |    0
 src/user/lib/include/sys/times.h        |   13 -
 src/user/lib/include/sys/types.h        |   18 -
 src/user/lib/include/sys/wait.h         |   13 -
 src/user/lib/include/termios.h          |    0
 src/user/lib/include/thread.h           |    9 -
 src/user/lib/include/time.h             |   34 -
 src/user/lib/include/unistd.h           |   64 -
 src/user/lib/intr.s                     |   20 -
 src/user/lib/math.c                     |   27 -
 src/user/lib/mman.c                     |   24 -
 src/user/lib/printf.c                   |   56 -
 src/user/lib/pwd.c                      |   23 -
 src/user/lib/setjmp.s                   |   39 -
 src/user/lib/signal.c                   |  100 -
 src/user/lib/stdio/file.c               |  359 --
 src/user/lib/stdio/file.h               |   14 -
 src/user/lib/stdio/misc.c               |   52 -
 src/user/lib/stdlib.c                   |  148 -
 src/user/lib/string/strerror.c          |   13 -
 src/user/lib/string/string.c            |  122 -
 src/user/lib/syscall.c                  |  104 -
 src/user/lib/syscall.c.awk              |   51 -
 src/user/lib/syscall.s                  |    9 -
 src/user/lib/sysstat.c                  |   50 -
 src/user/lib/syswait.c                  |   22 -
 src/user/lib/thread.S                   |   40 -
 src/user/lib/time.c                     |   43 -
 src/user/lib/unistd.c                   |  267 --
 src/user/lib/vendor/dlmalloc/malloc.c   | 6280 -------------------------------
 src/user/lib/vendor/dlmalloc/malloc.h   |  620 ---
 src/user/lib/vendor/getopt/getopt.c     |   75 -
 src/user/lib/vendor/getopt/getopt.h     |   21 -
 92 files changed, 10851 deletions(-)
 delete mode 100644 src/user/lib/_start.s
 delete mode 100644 src/user/lib/_start2.c
 delete mode 100644 src/user/lib/assert.c
 delete mode 100644 src/user/lib/camellia.c
 delete mode 100644 src/user/lib/compat.c
 delete mode 100644 src/user/lib/ctype.c
 delete mode 100644 src/user/lib/dirent.c
 delete mode 100644 src/user/lib/draw/draw.c
 delete mode 100644 src/user/lib/draw/flush.c
 delete mode 100644 src/user/lib/elf.h
 delete mode 100644 src/user/lib/elfload.S
 delete mode 100644 src/user/lib/elfload.c
 delete mode 100644 src/user/lib/elfreloc.c
 delete mode 100644 src/user/lib/err.c
 delete mode 100644 src/user/lib/esemaphore.c
 delete mode 100644 src/user/lib/fcntl.c
 delete mode 100644 src/user/lib/fs/dir.c
 delete mode 100644 src/user/lib/fs/dirinject.c
 delete mode 100644 src/user/lib/fs/misc.c
 delete mode 100644 src/user/lib/fs/whitelist.c
 delete mode 100644 src/user/lib/include/__errno.h
 delete mode 100644 src/user/lib/include/__errno.h.awk
 delete mode 100644 src/user/lib/include/_proc.h
 delete mode 100644 src/user/lib/include/alloca.h
 delete mode 100644 src/user/lib/include/bits/file.h
 delete mode 100644 src/user/lib/include/bits/panic.h
 delete mode 100644 src/user/lib/include/camellia.h
 delete mode 100644 src/user/lib/include/camellia/compat.h
 delete mode 100644 src/user/lib/include/camellia/fs/dir.h
 delete mode 100644 src/user/lib/include/camellia/fs/misc.h
 delete mode 100644 src/user/lib/include/ctype.h
 delete mode 100644 src/user/lib/include/dirent.h
 delete mode 100644 src/user/lib/include/draw.h
 delete mode 100644 src/user/lib/include/elfload.h
 delete mode 100644 src/user/lib/include/err.h
 delete mode 100644 src/user/lib/include/errno.h
 delete mode 100644 src/user/lib/include/esemaphore.h
 delete mode 100644 src/user/lib/include/fcntl.h
 delete mode 100644 src/user/lib/include/ftw.h
 delete mode 120000 src/user/lib/include/getopt.h
 delete mode 100644 src/user/lib/include/grp.h
 delete mode 100644 src/user/lib/include/inttypes.h
 delete mode 100644 src/user/lib/include/limits.h
 delete mode 100644 src/user/lib/include/locale.h
 delete mode 120000 src/user/lib/include/malloc.h
 delete mode 100644 src/user/lib/include/math.h
 delete mode 100644 src/user/lib/include/pwd.h
 delete mode 100644 src/user/lib/include/setjmp.h
 delete mode 100644 src/user/lib/include/signal.h
 delete mode 100644 src/user/lib/include/stdio.h
 delete mode 100644 src/user/lib/include/stdlib.h
 delete mode 100644 src/user/lib/include/string.h
 delete mode 100644 src/user/lib/include/strings.h
 delete mode 100644 src/user/lib/include/sys/ioctl.h
 delete mode 100644 src/user/lib/include/sys/mman.h
 delete mode 100644 src/user/lib/include/sys/param.h
 delete mode 100644 src/user/lib/include/sys/resource.h
 delete mode 100644 src/user/lib/include/sys/stat.h
 delete mode 100644 src/user/lib/include/sys/sysmacros.h
 delete mode 100644 src/user/lib/include/sys/time.h
 delete mode 100644 src/user/lib/include/sys/times.h
 delete mode 100644 src/user/lib/include/sys/types.h
 delete mode 100644 src/user/lib/include/sys/wait.h
 delete mode 100644 src/user/lib/include/termios.h
 delete mode 100644 src/user/lib/include/thread.h
 delete mode 100644 src/user/lib/include/time.h
 delete mode 100644 src/user/lib/include/unistd.h
 delete mode 100644 src/user/lib/intr.s
 delete mode 100644 src/user/lib/math.c
 delete mode 100644 src/user/lib/mman.c
 delete mode 100644 src/user/lib/printf.c
 delete mode 100644 src/user/lib/pwd.c
 delete mode 100644 src/user/lib/setjmp.s
 delete mode 100644 src/user/lib/signal.c
 delete mode 100644 src/user/lib/stdio/file.c
 delete mode 100644 src/user/lib/stdio/file.h
 delete mode 100644 src/user/lib/stdio/misc.c
 delete mode 100644 src/user/lib/stdlib.c
 delete mode 100644 src/user/lib/string/strerror.c
 delete mode 100644 src/user/lib/string/string.c
 delete mode 100644 src/user/lib/syscall.c
 delete mode 100644 src/user/lib/syscall.c.awk
 delete mode 100644 src/user/lib/syscall.s
 delete mode 100644 src/user/lib/sysstat.c
 delete mode 100644 src/user/lib/syswait.c
 delete mode 100644 src/user/lib/thread.S
 delete mode 100644 src/user/lib/time.c
 delete mode 100644 src/user/lib/unistd.c
 delete mode 100644 src/user/lib/vendor/dlmalloc/malloc.c
 delete mode 100644 src/user/lib/vendor/dlmalloc/malloc.h
 delete mode 100644 src/user/lib/vendor/getopt/getopt.c
 delete mode 100644 src/user/lib/vendor/getopt/getopt.h

(limited to 'src/user/lib')

diff --git a/src/user/lib/_start.s b/src/user/lib/_start.s
deleted file mode 100644
index 12d2c5f..0000000
--- a/src/user/lib/_start.s
+++ /dev/null
@@ -1,17 +0,0 @@
-.section .text
-.global _start
-.type _start, @function
-.weak _start
-_start:
-	mov %rsp, %rdi
-	and $~0xF, %rsp
-
-	/* prevent floating point crashes. thanks heat */
-	push $0x1f80
-	ldmxcsr (%rsp)
-	add $8, %rsp
-
-	call _start2
-	hlt
-	/* the call shouldn't return, thus the hlt.
-	 * using a call instead of jmp for stack alignment */
diff --git a/src/user/lib/_start2.c b/src/user/lib/_start2.c
deleted file mode 100644
index b4eb76a..0000000
--- a/src/user/lib/_start2.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <_proc.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <elfload.h>
-
-int main(int argc, char **argv, char **envp);
-
-__attribute__((visibility("hidden")))
-extern char __executable_start[];
-
-const char *shortname(const char *path) {
-	if (!path) return "unknown program";
-	const char *slash = strrchr(path, '/');
-	if (slash) return slash + 1;
-	return path;
-}
-
-void intr_trampoline(void); /* intr.s */
-
-_Noreturn void _start2(struct execdata *ed) {
-	const char *progname;
-	elf_selfreloc();
-
-	/* done first so it isn't allocated elsewhere by accident */
-	_sys_memflag(_psdata_loc, 1, MEMFLAG_PRESENT);
-	_psdata_loc->base = __executable_start;
-	/* sets ->desc */
-	progname = shortname(ed->argv[0]);
-	setprogname(progname);
-
-	_klogf("_start2 %s %p", progname, __executable_start);
-
-	_sys_intr_set(intr_trampoline);
-	intr_set(intr_default);
-	__setinitialcwd(ed->cwd);
-
-	exit(main(ed->argc, ed->argv, ed->envp));
-}
diff --git a/src/user/lib/assert.c b/src/user/lib/assert.c
deleted file mode 100644
index 0c46450..0000000
--- a/src/user/lib/assert.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <assert.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-
-_Noreturn void __badassert(const char *func, const char *file, int line) {
-	fprintf(stderr, "assertion failure %s:%s:%u\n", file, func, line);
-	_sys_exit(1);
-}
diff --git a/src/user/lib/camellia.c b/src/user/lib/camellia.c
deleted file mode 100644
index 4e092e4..0000000
--- a/src/user/lib/camellia.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-hid_t camellia_open(const char *path, int flags) {
-	hid_t ret;
-	char *buf;
-	size_t len;
-
-	if (path == NULL)
-		return errno = EINVAL, -EINVAL;
-	if (flags & OPEN_CREATE)
-		flags |= OPEN_WRITE;
-
-	len = absolutepath(NULL, path, 0);
-	buf = malloc(len);
-	if (!buf)
-		return -errno;
-	absolutepath(buf, path, len);
-	ret = _sys_open(buf, strlen(buf), flags);
-	free(buf);
-
-	if (ret < 0)
-		errno = -ret;
-
-	return ret;
-}
diff --git a/src/user/lib/compat.c b/src/user/lib/compat.c
deleted file mode 100644
index 3ec47f9..0000000
--- a/src/user/lib/compat.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <camellia/compat.h>
-
-#define eprintf(fmt, ...) fprintf(stderr, "user/lib/compat: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-static hid_t h = -1;
-long c0_fs_wait(char *buf, long len, struct ufs_request *res) {
-	if (h != -1) {
-		eprintf("didn't respond to request!");
-		c0_fs_respond(NULL, -1, 0);
-	}
-	h = _sys_fs_wait(buf, len, res);
-	return h >= 0 ? 0 : -1;
-}
-long c0_fs_respond(void *buf, long ret, int flags) {
-	ret = _sys_fs_respond(h, buf, ret, flags);
-	h = -1;
-	return ret;
-}
diff --git a/src/user/lib/ctype.c b/src/user/lib/ctype.c
deleted file mode 100644
index fa49a07..0000000
--- a/src/user/lib/ctype.c
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <ctype.h>
-
-int isalnum(int c) {
-	return isalpha(c) || isdigit(c);
-}
-
-int isalpha(int c) {
-	return islower(c) || isupper(c);
-}
-
-int iscntrl(int c) {
-	return c <= 0x1f || c == 0x7f;
-}
-
-int isdigit(int c) {
-	return '0' <= c && c <= '9';
-}
-
-int isgraph(int c) {
-	return isalpha(c) || isdigit(c) || ispunct(c);
-}
-
-int islower(int c) {
-	return 'a' <= c && c <= 'z';
-}
-
-int isprint(int c) {
-	return isgraph(c) || c == ' ';
-}
-
-int ispunct(int c) {
-	return ('!' <= c && c <= '/')
-		|| (':' <= c && c <= '@')
-		|| ('[' <= c && c <= '`')
-		|| ('{' <= c && c <= '~');
-}
-
-int isspace(int c) {
-	return c == ' '
-		|| c == '\f'
-		|| c == '\n'
-		|| c == '\r'
-		|| c == '\t'
-		|| c == '\v';
-}
-
-int isupper(int c) {
-	return 'A' <= c && c <= 'Z';
-}
-
-int isxdigit(int c) {
-	return ('0' <= c && c <= '9')
-		|| ('A' <= c && c <= 'F')
-		|| ('a' <= c && c <= 'f');
-}
-
-int tolower(int c) {
-	if (isupper(c)) return c - 'A' + 'a';
-	return c;
-}
-
-int toupper(int c) {
-	if (islower(c)) return c - 'a' + 'A';
-	return c;
-}
diff --git a/src/user/lib/dirent.c b/src/user/lib/dirent.c
deleted file mode 100644
index c2d1b9c..0000000
--- a/src/user/lib/dirent.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-DIR *opendir(const char *name) {
-	FILE *fp = NULL;
-	DIR *dir = NULL;
-	fp = fopen(name, "r");
-	if (!fp) {
-		goto err;
-	}
-	dir = calloc(1, sizeof *dir);
-	if (!dir) {
-		goto err;
-	}
-	dir->fp = fp;
-	return dir;
-err:
-	if (fp) fclose(fp);
-	free(dir);
-	return NULL;
-}
-
-int closedir(DIR *dir) {
-	fclose(dir->fp);
-	free(dir);
-	return 0;
-}
-
-struct dirent *readdir(DIR *dir) {
-	int i = 0;
-	char *buf = dir->dent.d_name;
-	for (;;) {
-		int c = fgetc(dir->fp);
-		if (c == EOF) {
-			if (i == 0) return NULL;
-			else break;
-		}
-		if (c == '\0') {
-			break;
-		}
-		if (i == sizeof(dir->dent.d_name)-1) {
-			/* overflow */
-			for (;;) {
-				c = fgetc(dir->fp);
-				if (c == EOF || c == '\0') break;
-			}
-			return errno = ENAMETOOLONG, NULL;
-		}
-		buf[i++] = c;
-	}
-	buf[i] = '\0';
-	return &dir->dent;
-}
diff --git a/src/user/lib/draw/draw.c b/src/user/lib/draw/draw.c
deleted file mode 100644
index 1c2a371..0000000
--- a/src/user/lib/draw/draw.c
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <draw.h>
-
-void dirty_reset(struct rect *d) {
-	d->x1 = ~0; d->y1 = ~0;
-	d->x2 =  0; d->y2 =  0;
-}
-
-void dirty_mark(struct rect *d, uint32_t x, uint32_t y) {
-	if (d->x1 > x) d->x1 = x;
-	if (d->x2 < x) d->x2 = x;
-	if (d->y1 > y) d->y1 = y;
-	if (d->y2 < y) d->y2 = y;
-}
-
-int fb_setup(struct framebuf *fb, const char *base) {
-	char path[64], *spec;
-	size_t pos;
-	FILE *f;
-
-	f = fopen(base, "r");
-	if (!f) return -errno;
-
-	pos = strlen(base);
-	memcpy(path, base, pos);
-	spec = path + pos;
-	fread(spec, 1, sizeof(path) - pos, f);
-	/* assumes the read went correctly */
-	fclose(f);
-
-	fb->fd = camellia_open(path, OPEN_RW);
-	if (fb->fd < 0) return fb->fd;
-
-	fb->width  = strtol(spec, &spec, 0);
-	if (*spec++ != 'x') return -EINVAL;
-	fb->height = strtol(spec, &spec, 0);
-	if (*spec++ != 'x') return -EINVAL;
-	fb->bpp = strtol(spec, &spec, 0);
-	if (fb->bpp != 32) return -EINVAL;
-
-	fb->len = _sys_getsize(fb->fd);
-	fb->pitch = fb->len / fb->height;
-	fb->b = malloc(fb->len);
-
-	_sys_read(fb->fd, fb->b, fb->len, 0);
-
-	return 0;
-}
-
-int fb_anon(struct framebuf *fb, size_t w, size_t h) {
-	fb->width  = w;
-	fb->height = h;
-	fb->bpp = 32;
-	fb->pitch = fb->width * fb->bpp / 8;
-	fb->len = fb->pitch * fb->height;
-	fb->b = malloc(fb->len);
-	fb->fd = -1;
-	return 0;
-}
-
-uint32_t *fb_pixel(struct framebuf *fb, uint32_t x, uint32_t y) {
-	if (x < fb->width && y < fb->height)
-		return (void*)fb->b + fb->pitch * y + 4 * x;
-	return NULL;
-}
-
-void fb_cpy(
-	struct framebuf *dest, const struct framebuf *src,
-	size_t xd, size_t yd, size_t xs, size_t ys, size_t w, size_t h)
-{
-	for (size_t y = 0; y < h; y++) {
-		memcpy(
-			fb_pixel(      dest, xd, yd + y),
-			fb_pixel((void*)src, xs, ys + y),
-			w * 4
-		);
-	}
-}
diff --git a/src/user/lib/draw/flush.c b/src/user/lib/draw/flush.c
deleted file mode 100644
index 88bf3d6..0000000
--- a/src/user/lib/draw/flush.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <camellia/execbuf.h>
-#include <camellia/syscalls.h>
-#include <draw.h>
-
-static void flush_combined(struct rect pix, struct framebuf *fb) {
-	size_t low  = fb->pitch * pix.y1 + 4 * pix.x1;
-	size_t high = fb->pitch * pix.y2 + 4 * pix.y2 + 4;
-	_sys_write(fb->fd, fb->b + low, high - low, low, 0);
-}
-
-static void flush_split(struct rect pix, struct framebuf *fb) {
-	static uint64_t execbuf[EXECBUF_MAX_LEN / sizeof(uint64_t)];
-	size_t epos = 0;
-	if (7 * (pix.y2 - pix.y1) * sizeof(uint64_t) >= sizeof execbuf) {
-		flush_combined(pix, fb);
-		return;
-	}
-
-	for (uint32_t y = pix.y1; y < pix.y2; y++) {
-		size_t low  = fb->pitch * y + 4 * pix.x1;
-		size_t high = fb->pitch * y + 4 * pix.x2 + 4;
-
-		execbuf[epos++] = EXECBUF_SYSCALL;
-		execbuf[epos++] = _SYS_WRITE;
-		execbuf[epos++] = fb->fd;
-		execbuf[epos++] = (uintptr_t)fb->b + low;
-		execbuf[epos++] = high - low;
-		execbuf[epos++] = low;
-		execbuf[epos++] = 0;
-	}
-	_sys_execbuf(execbuf, epos * sizeof(uint64_t));
-}
-
-void dirty_flush(struct rect *d, struct framebuf *fb) {
-	if (~d->x1 == 0) return;
-	if (d->x2 >= fb->width)  d->x2 = fb->width - 1;
-	if (d->y2 >= fb->height) d->y2 = fb->height - 1;
-
-	/* the threshold is mostly arbitrary, wasn't based on any real benchmarks */
-	if (d->x2 - d->x1 > fb->width - 600) flush_combined(*d, fb);
-	else flush_split(*d, fb);
-	dirty_reset(d);
-}
diff --git a/src/user/lib/elf.h b/src/user/lib/elf.h
deleted file mode 100644
index 8dc6242..0000000
--- a/src/user/lib/elf.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/* shamelessly stolen from https://github.com/adachristine/sophia/tree/main/api/elf */
-#pragma once
-#include <stdint.h>
-
-typedef uint8_t Elf_Byte;
-
-#define EI_MAG0 0
-#define EI_MAG1 1
-#define EI_MAG2 2
-#define EI_MAG3 3
-#define EI_CLASS 4
-#define EI_DATA 5
-#define EI_VERSION 6
-#define EI_OSABI 7
-#define EI_ABIVERSION 8
-#define EI_PAD 9
-#define EI_NIDENT 16
-
-#define ELFMAG0 0x7f
-#define ELFMAG1 'E'
-#define ELFMAG2 'L'
-#define ELFMAG3 'F'
-
-#define ELFCLASSNONE 0
-#define ELFCLASS32 1
-#define ELFCLASS64 2
-
-#define ELFDATANONE 0
-#define ELFDATA2LSB 1
-#define ELFDATA2MSB 2
-
-#define EI_VERSION 6
-#define EV_NONE 0
-#define EV_CURRENT 1
-
-#define ELFOSABI_NONE 0
-#define ELFOSABI_SYSV EI_OSABI_NONE
-
-#define ET_NONE 0
-#define ET_REL 1
-#define ET_EXEC 2
-#define ET_DYN 3
-#define ET_CORE 4
-#define ET_LOOS 0xfe00
-#define ET_HIOS 0xfeff
-
-#define EM_NONE 0
-
-#define PT_NULL 0
-#define PT_LOAD 1
-#define PT_DYNAMIC 2
-
-#define PF_X 0x01
-#define PF_W 0x02
-#define PF_R 0x04
-
-#define SHT_NULL 0
-#define SHT_PROGITS 1
-#define SHT_SYMTAB 2
-#define SHT_STRTAB 3
-#define SHT_RELA 4
-#define SHT_HASH 5
-#define SHT_DYNAMIC 6
-
-#define SHF_WRITE 0x1
-#define SHF_ALLOC 0x2
-#define SHF_EXEC  0x4
-#define SHF_MERGE 0x10
-#define SHF_STRINGS 0x20
-
-#define DT_NULL 0
-#define DT_NEEDED 1
-#define DT_PLTRELSZ 2
-#define DT_PLTGOT 3
-#define DT_HASH 4
-#define DT_STRTAB 5
-#define DT_SYMTAB 6
-#define DT_RELA 7
-#define DT_RELASZ 8
-#define DT_RELAENT 9
-#define DT_STRSZ 10
-#define DT_SYMENT 11
-#define DT_JMPREL 0x17
-
-typedef uint64_t Elf64_Addr;
-typedef uint64_t Elf64_Off;
-typedef uint16_t Elf64_Section;
-typedef uint16_t Elf64_Versym;
-typedef uint16_t Elf64_Half;
-typedef int32_t Elf64_Sword;
-typedef uint32_t Elf64_Word;
-typedef int64_t Elf64_Sxword;
-typedef uint64_t Elf64_Xword;
-
-typedef struct Elf64_Ehdr Elf64_Ehdr;
-typedef struct Elf64_Phdr Elf64_Phdr;
-typedef struct Elf64_Shdr Elf64_Shdr;
-typedef struct Elf64_Sym Elf64_Sym;
-typedef struct Elf64_Dyn Elf64_Dyn;
-
-typedef struct Elf64_Rel Elf64_Rel;
-typedef struct Elf64_Rela Elf64_Rela;
-
-#define EM_X86_64 62
-
-struct Elf64_Ehdr
-{
-    Elf_Byte e_ident[EI_NIDENT];
-    Elf64_Half e_type;
-    Elf64_Half e_machine;
-    Elf64_Word e_version;
-    Elf64_Addr e_entry;
-    Elf64_Off e_phoff;
-    Elf64_Off e_shoff;
-    Elf64_Word e_flags;
-    Elf64_Half e_ehsize;
-    Elf64_Half e_phentsize;
-    Elf64_Half e_phnum;
-    Elf64_Half e_shentsize;
-    Elf64_Half e_shnum;
-    Elf64_Half e_shstrndx;
-};
-
-struct Elf64_Phdr
-{
-    Elf64_Word p_type;
-    Elf64_Word p_flags;
-    Elf64_Off p_offset;
-    Elf64_Addr p_vaddr;
-    Elf64_Addr p_paddr;
-    Elf64_Xword p_filesz;
-    Elf64_Xword p_memsz;
-    Elf64_Xword p_align;
-};
-
-struct Elf64_Shdr
-{
-    Elf64_Word sh_name;
-    Elf64_Word sh_type;
-    Elf64_Xword sh_flags;
-    Elf64_Addr sh_addr;
-    Elf64_Off sh_offset;
-    Elf64_Xword sh_size;
-    Elf64_Word sh_link;
-    Elf64_Word sh_info;
-    Elf64_Off sh_addralign;
-    Elf64_Xword sh_entsize;
-};
-
-struct Elf64_Sym
-{
-    Elf64_Word st_name;
-    Elf_Byte st_info;
-    Elf_Byte st_other;
-    Elf64_Half st_shndx;
-    Elf64_Addr st_value;
-    Elf64_Xword st_size;
-};
-
-struct Elf64_Dyn
-{
-    Elf64_Xword d_tag;
-    union
-    {
-        Elf64_Xword d_val;
-        Elf64_Addr d_ptr;
-    };
-};
-
-#define ELF64_R_SYM(info) ((info)>>32)
-#define ELF64_R_TYPE(info) ((Elf64_Word)(info))
-#define ELF64_R_INFO(sym, type) (((Elf64_Xword)(sym)<<32)+(Elf64_Xword)(type))
-
-#define R_X86_64_JUMP_SLOT 7
-#define R_X86_64_RELATIVE 8
-
-struct Elf64_Rel
-{
-    Elf64_Addr r_offset;
-    Elf64_Xword r_info;
-};
-
-struct Elf64_Rela
-{
-    Elf64_Addr r_offset;
-    Elf64_Xword r_info;
-    Elf64_Sxword r_addend;
-};
diff --git a/src/user/lib/elfload.S b/src/user/lib/elfload.S
deleted file mode 100644
index 78d5b3c..0000000
--- a/src/user/lib/elfload.S
+++ /dev/null
@@ -1,20 +0,0 @@
-#define ASM_FILE 1
-#include <camellia/syscalls.h>
-
-.section .text
-.global _freejmp_chstack
-.type _freejmp_chstack, @function
-// void _freejmp_chstack(void *entry, void *low, size_t len, char **argv, char **envp, void *stack);
-_freejmp_chstack:
-	mov %r9, %rsp
-	jmp _freejmp
-
-.section .text
-.global execbuf_chstack
-.type execbuf_chstack, @function
-// _Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len);
-execbuf_chstack:
-	mov %rdi, %rsp
-	mov $_SYS_EXECBUF, %rdi
-	syscall
-	hlt // if execbuf failed we might as well crash
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c
deleted file mode 100644
index c1a08f8..0000000
--- a/src/user/lib/elfload.c
+++ /dev/null
@@ -1,182 +0,0 @@
-#include <camellia/execbuf.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "elf.h"
-#include <elfload.h>
-
-void elf_execf(FILE *f, char **argv, char **envp) {
-	size_t ret;
-	void *buf;
-	long buflen;
-
-	fseek(f, 0, SEEK_END);
-	buflen = ftell(f);
-	if (buflen < 0) return; /* errno set by fseek */
-	buf = malloc(buflen);
-
-	// TODO don't read the entire file into memory
-	fseek(f, 0, SEEK_SET);
-	if (!buf) return;
-	ret = fread(buf, buflen, 1, f);
-	fclose(f);
-	if (ret == 1) {
-		elf_exec(buf, argv, envp);
-	}
-	free(buf);
-}
-
-static bool valid_ehdr(const struct Elf64_Ehdr *h) {
-	return h->e_ident[0] == 0x7f
-		&& h->e_ident[1] == 'E'
-		&& h->e_ident[2] == 'L'
-		&& h->e_ident[3] == 'F'
-		&& h->e_machine == EM_X86_64
-		&& h->e_version == 1;
-}
-
-static bool load_phdr(const void *elf, void *exebase, size_t idx) {
-	const struct Elf64_Ehdr *ehdr = elf;
-	const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + idx * ehdr->e_phentsize;
-
-	if (phdr->p_type == PT_DYNAMIC) return true;
-
-	if (phdr->p_type != PT_LOAD) {
-		printf("unknown type %x\n", phdr->p_type);
-		return false;
-	}
-	// TODO overlap check
-	// TODO don't ignore flags
-	_sys_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT);
-	// TODO check that filesz <= memsz
-	memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz);
-	return true;
-}
-
-static size_t elf_spread(const void *elf) {
-	const struct Elf64_Ehdr *ehdr = elf;
-	uintptr_t high = 0, low = ~0;
-	for (size_t phi = 0; phi < ehdr->e_phnum; phi++) {
-		const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + phi * ehdr->e_phentsize;
-		if (high < phdr->p_vaddr + phdr->p_memsz)
-			high = phdr->p_vaddr + phdr->p_memsz;
-		if (low > phdr->p_vaddr)
-			low = phdr->p_vaddr;
-	}
-	return high - low;
-}
-
-static void *memdup(const void *orig, size_t len) {
-	void *n = malloc(len);
-	if (n) memcpy(n, orig, len);
-	return n;
-}
-
-static const char *default_argv[] = {NULL};
-
-/* frees memory outside of [low; low + len] and jumps to *entry
- * also sets up main's stack */
-void _freejmp_chstack(void *entry, void *low, size_t len, const char **argv, char **envp, void *stack); // elfload.s
-_Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len);
-void _freejmp(void *entry, void *low, size_t imglen, const char **argv, char **envp) {
-	// TODO error checking
-	// although i guess it's fine for it to crash
-	// also TODO just alloc a new stack
-	void *stack = (void*)~0;
-	struct execdata ed;
-	size_t argv_len;
-	size_t cwd_len = absolutepath(NULL, NULL, 0);
-
-	if (!argv) argv = default_argv;
-
-	ed.argc = 0;
-	while (argv[ed.argc]) ed.argc++;
-	argv_len = (ed.argc+1) * sizeof(char *);
-
-	/* make a copy of argv, so it doesn't get overridden
-	 * if it overlaps with the new stack. */
-	argv = memdup(argv, argv_len);
-	for (int i = 0; i < ed.argc; i++) {
-		argv[i] = strdup(argv[i]);
-	}
-	ed.cwd = malloc(cwd_len);
-	getcwd(ed.cwd, cwd_len);
-
-	stack -= argv_len;
-	ed.argv = stack;
-
-	for (int i = 0; i < ed.argc; i++) {
-		size_t len = strlen(argv[i]) + 1;
-		stack -= len;
-		memcpy(stack, argv[i], len);
-		ed.argv[i] = stack;
-	}
-	ed.argv[ed.argc] = NULL;
-
-	/* push cwd */
-	stack -= cwd_len;
-	memcpy(stack, ed.cwd, cwd_len);
-	ed.cwd = stack;
-
-	stack -= sizeof ed;
-	memcpy(stack, &ed, sizeof ed);
-
-	uintptr_t high = (uintptr_t)low + imglen;
-	uint64_t buf[] = {
-		EXECBUF_SYSCALL, _SYS_MEMFLAG, 0, (uintptr_t)low, 0, 0, 0,
-		EXECBUF_SYSCALL, _SYS_MEMFLAG, high, ~0 - 0xF000 - high, 0, 0, 0,
-		EXECBUF_JMP, (uintptr_t)entry,
-	};
-	execbuf_chstack(stack, buf, sizeof buf);
-}
-
-static void *elf_loadmem(struct Elf64_Ehdr *ehdr) {
-	void *exebase;
-	size_t spread = elf_spread(ehdr);
-	switch (ehdr->e_type) {
-		case ET_EXEC:
-			exebase = (void*)0;
-			break;
-		case ET_DYN:
-			exebase = _sys_memflag((void*)0x1000, spread, MEMFLAG_FINDFREE);
-			if (!exebase)
-				return NULL;
-			break;
-		default:
-			return NULL;
-	}
-	for (size_t phi = 0; phi < ehdr->e_phnum; phi++) {
-		if (!load_phdr((void*)ehdr, exebase, phi)) {
-			_sys_memflag(exebase, spread, 0);
-			return NULL;
-		}
-	}
-	return exebase;
-}
-
-void elf_exec(void *base, char **argv, char **envp) {
-	struct Elf64_Ehdr *ehdr = base;
-	if (!valid_ehdr(ehdr)) return;
-
-	void *exebase = elf_loadmem(ehdr);
-	if (!exebase) return;
-
-	void *newstack = _sys_memflag((void*)0x11000, 0x1000, MEMFLAG_FINDFREE | MEMFLAG_PRESENT) + 0x1000 - 8;
-	if (!newstack) return;
-
-	_freejmp_chstack(exebase + ehdr->e_entry, exebase, elf_spread(ehdr) + 0x1000, (const char**)argv, envp, newstack);
-}
-
-void *elf_partialexec(void *base) {
-	struct Elf64_Ehdr *ehdr = base;
-	if (!valid_ehdr(ehdr)) return NULL;
-
-	void *exebase = elf_loadmem(ehdr);
-	if (!exebase) return NULL;
-
-	return exebase + ehdr->e_entry;
-}
diff --git a/src/user/lib/elfreloc.c b/src/user/lib/elfreloc.c
deleted file mode 100644
index aab2a2a..0000000
--- a/src/user/lib/elfreloc.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stdio.h>
-#include "elf.h"
-
-__attribute__((visibility("hidden")))
-extern struct Elf64_Dyn _DYNAMIC[];
-
-__attribute__((visibility("hidden")))
-extern char __executable_start[];
-
-static struct Elf64_Dyn *dyn_gettag(Elf64_Xword tag) {
-	for (size_t i = 0;; i++) {
-		if (_DYNAMIC[i].d_tag == tag) return &_DYNAMIC[i];
-		if (_DYNAMIC[i].d_tag == DT_NULL) return NULL;
-	}
-}
-
-void elf_selfreloc(void) {
-	// TODO DT_REL, DT_JMPREL
-
-	struct Elf64_Dyn *rela_tag = dyn_gettag(DT_RELA);
-	if (rela_tag) {
-		/* not checking pointer validity,
-		 * crashing on an invalid elf is fine */
-		size_t relasz = dyn_gettag(DT_RELASZ)->d_val;
-		size_t relaent = dyn_gettag(DT_RELAENT)->d_val;
-		for (size_t o = 0; o < relasz; o += relaent) {
-			struct Elf64_Rela *r = (void*)__executable_start + rela_tag->d_ptr + o;
-			uintptr_t *target = (void*)__executable_start + r->r_offset;
-
-			switch (ELF64_R_TYPE(r->r_info)) {
-				case R_X86_64_RELATIVE:
-					*target = (uintptr_t)&__executable_start + r->r_addend;
-					break;
-				default:
-					_klogf("elf: unsupported relocation type\n");
-			}
-		}
-	}
-}
diff --git a/src/user/lib/err.c b/src/user/lib/err.c
deleted file mode 100644
index 7a220fe..0000000
--- a/src/user/lib/err.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-_Noreturn void err(int ret, const char *fmt, ...) {
-	va_list args;
-	va_start(args, fmt);
-	vwarn(fmt, args);
-	va_end(args);
-	exit(ret);
-}
-
-_Noreturn void errx(int ret, const char *fmt, ...) {
-	va_list args;
-	va_start(args, fmt);
-	vwarnx(fmt, args);
-	va_end(args);
-	exit(ret);
-}
-
-void warn(const char *fmt, ...) {
-	va_list args;
-	va_start(args, fmt);
-	vwarn(fmt, args);
-	va_end(args);
-}
-
-void warnx(const char *fmt, ...) {
-	va_list args;
-	va_start(args, fmt);
-	vwarnx(fmt, args);
-	va_end(args);
-}
-
-void vwarn(const char *fmt, va_list args) {
-	fprintf(stderr, "%s: ", getprogname());
-	if (fmt) {
-		vfprintf(stderr, fmt, args);
-		fprintf(stderr, ": ");
-	}
-	fprintf(stderr, "%s\n", strerror(errno));
-}
-
-void vwarnx(const char *fmt, va_list args) {
-	fprintf(stderr, "%s: ", getprogname());
-	if (fmt) vfprintf(stderr, fmt, args);
-	fprintf(stderr, "\n");
-}
diff --git a/src/user/lib/esemaphore.c b/src/user/lib/esemaphore.c
deleted file mode 100644
index 2707d11..0000000
--- a/src/user/lib/esemaphore.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <esemaphore.h>
-
-void esem_signal(struct evil_sem *sem) {
-	_sys_write(sem->signal, NULL, 0, 0, 0);
-}
-
-void esem_wait(struct evil_sem *sem) {
-	_sys_read(sem->wait, NULL, 0, 0);
-}
-
-struct evil_sem *esem_new(int value) {
-	hid_t ends_wait[2], ends_signal[2];
-	struct evil_sem *sem;
-
-	if (value < 0) return NULL;
-	if (_sys_pipe(ends_wait, 0) < 0) return NULL;
-	if (_sys_pipe(ends_signal, 0) < 0) goto fail_signal;
-	if (!(sem = malloc(sizeof *sem))) goto fail_malloc;
-
-	if (!_sys_fork(FORK_NOREAP, NULL)) {
-		close(ends_signal[1]);
-		while (_sys_read(ends_signal[0], NULL, 0, 0) >= 0) {
-			if (!_sys_fork(FORK_NOREAP, NULL)) {
-				_sys_write(ends_wait[1], NULL, 0, 0, 0);
-				exit(0);
-			}
-		}
-		exit(0);
-	}
-	close(ends_signal[0]);
-	close(ends_wait[1]);
-
-	sem->wait = ends_wait[0];
-	sem->signal = ends_signal[1];
-
-	while (value--) esem_signal(sem);
-	return sem;
-
-fail_malloc:
-	close(ends_signal[0]);
-	close(ends_signal[1]);
-fail_signal:
-	close(ends_wait[0]);
-	close(ends_wait[1]);
-	return NULL;
-}
-
-void esem_free(struct evil_sem *sem) {
-	close(sem->wait);
-	close(sem->signal);
-	free(sem);
-}
diff --git a/src/user/lib/fcntl.c b/src/user/lib/fcntl.c
deleted file mode 100644
index b2d8685..0000000
--- a/src/user/lib/fcntl.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-
-#include <stdio.h>
-
-int open(const char *path, int flags, ...) {
-	(void)path; (void)flags;
-	_klogf("failing open(\"%s\")", path);
-	return errno = ENOSYS, -1;
-}
-
-int fcntl(int fd, int cmd, ...) {
-	va_list argp;
-	va_start(argp, cmd);
-	if (cmd == F_DUPFD) {
-		int to = va_arg(argp, int);
-		va_end(argp);
-		return _sys_dup(fd, to, DUP_SEARCH);
-	} else {
-		va_end(argp);
-		_klogf("failing fcntl(%d)", cmd);
-		return errno = ENOSYS, -1;
-	}
-}
diff --git a/src/user/lib/fs/dir.c b/src/user/lib/fs/dir.c
deleted file mode 100644
index b7f840d..0000000
--- a/src/user/lib/fs/dir.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <camellia/fs/dir.h>
-
-void dir_start(struct dirbuild *db, long offset, char *buf, size_t buflen) {
-	db->offset = offset;
-	db->buf = buf;
-	db->bpos = 0;
-	db->blen = buflen;
-	db->error = 0;
-
-	// TODO decide how negative directory offsets should be handled
-	if (offset < 0) db->error = -ENOSYS;
-}
-
-bool dir_append(struct dirbuild *db, const char *name) {
-	return dir_appendl(db, name, strlen(name));
-}
-
-bool dir_appendl(struct dirbuild *db, const char *name, size_t len) {
-	if (db->error) return true;
-	if (len > (size_t)LONG_MAX) {
-		db->error = -1;
-		return true;
-	}
-
-	len++; // account for the null byte
-
-	if (db->offset < (long)len) {
-		name += db->offset;
-		len  -= db->offset;
-		db->offset = 0;
-
-		if (db->buf) {
-			// TODO no buffer overrun check
-			memcpy(db->buf + db->bpos, name, len - 1);
-			db->buf[db->bpos + len - 1] = '\0';
-		}
-		db->bpos += len;
-	} else {
-		db->offset -= len;
-	}
-	return false;
-}
-
-bool dir_append_from(struct dirbuild *db, hid_t h) {
-	if (db->error) return true;
-	if (db->buf && db->bpos == db->blen) return false;
-
-	int ret;
-	if (db->buf) {
-		ret = _sys_read(h, db->buf + db->bpos, db->blen - db->bpos, db->offset);
-		if (ret < 0) {
-			db->error = ret;
-			return true;
-		} else if (ret > 0) {
-			/* not eof */
-			db->offset = 0;
-			db->bpos += ret;
-			return false;
-		} /* else ret == 0, EOF, need getsize */
-	}
-
-	ret = _sys_getsize(h);
-	if (ret < 0) {
-		db->error = ret;
-		return true;
-	}
-	if (db->offset < ret) {
-		/* should only occur when !buf, otherwise leaks previous data from buf.
-		 * TODO consider impact */
-		db->bpos += ret - db->offset;
-		db->offset = 0;
-	} else {
-		db->offset -= ret;
-	}
-	return false;
-}
-
-long dir_finish(struct dirbuild *db) {
-	return db->error ? db->error : db->bpos;
-}
diff --git a/src/user/lib/fs/dirinject.c b/src/user/lib/fs/dirinject.c
deleted file mode 100644
index 9b08756..0000000
--- a/src/user/lib/fs/dirinject.c
+++ /dev/null
@@ -1,129 +0,0 @@
-#include <assert.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/param.h>
-#include <unistd.h>
-
-typedef struct Handle {
-	int delegate;
-	int plen;
-	char path[];
-} Handle;
-
-static int
-dir_seglen(const char *path)
-{
-	/* if path contains /, return its position + 1
-	 * otherwise, return strlen */
-	int len = 0;
-	while (path[len]) {
-		if (path[len] == '/') {
-			len++;
-			break;
-		}
-		len++;
-	}
-	return len;
-}
-
-static int
-find_injects(const char *injects[], const char *path, int plen, struct dirbuild *db)
-{
-	// TODO deduplicate
-	const char *inj;
-	int matches = 0;
-	assert(plen >= 1);
-	assert(path[plen-1] == '/');
-
-	while ((inj = *injects++)) {
-		int ilen = strlen(inj);
-		if (plen < ilen && memcmp(path, inj, plen) == 0) {
-			if (db) {
-				/* inj[plen-1] == '/' */
-				const char *ent = inj + plen;
-				dir_appendl(db, ent, dir_seglen(ent));
-			}
-			matches++;
-		}
-	}
-	return matches;
-}
-
-void
-fs_dirinject2(const char *injects[])
-{
-	const size_t buflen = 4096;
-	char *buf = malloc(buflen);
-	if (!buf) exit(1);
-
-	for (;;) {
-		struct ufs_request req;
-		hid_t reqh = _sys_fs_wait(buf, buflen, &req);
-		if (reqh < 0) break;
-		Handle *hndl = req.id;
-		switch (req.op) {
-		case VFSOP_OPEN: {
-			if (buf[req.len - 1] == '/') {
-				if (find_injects(injects, buf, req.len, NULL) > 0) {
-					/* opening a directory that we're injecting into */
-					hndl = malloc(sizeof(Handle) + req.len);
-					if (hndl == NULL) {
-						_sys_fs_respond(reqh, NULL, -EGENERIC, 0);
-						break;
-					}
-					/* ignore errors from _sys_open */
-					hndl->delegate = _sys_open(buf, req.len, req.flags);
-					hndl->plen = req.len;
-					memcpy(hndl->path, buf, hndl->plen);
-					_sys_fs_respond(reqh, hndl, 0, 0);
-					break;
-				}
-			}
-			/* default behaviour */
-			forward_open(reqh, buf, req.len, req.flags);
-			break;
-		}
-
-		case VFSOP_CLOSE: {
-			if (hndl->delegate >= 0) {
-				close(hndl->delegate);
-			}
-			free(hndl);
-			_sys_fs_respond(reqh, NULL, 0, 0);
-			break;
-		}
-
-		case VFSOP_READ:
-		case VFSOP_GETSIZE: {
-			struct dirbuild db;
-			char *target = NULL;
-			if (req.op == VFSOP_READ) {
-				target = buf;
-			}
-			req.capacity = MIN(req.capacity, buflen);
-
-			dir_start(&db, req.offset, target, req.capacity);
-			find_injects(injects, hndl->path, hndl->plen, &db);
-			if (hndl->delegate >= 0) {
-				dir_append_from(&db, hndl->delegate);
-			}
-			_sys_fs_respond(reqh, target, dir_finish(&db), 0);
-			break;
-		}
-
-		default: {
-			_sys_fs_respond(reqh, NULL, -1, 0);
-			break;
-		}
-		}
-	}
-	exit(0);
-}
-
-void
-fs_dirinject(const char *path) {
-	fs_dirinject2((const char*[]){ path, NULL });
-}
diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
deleted file mode 100644
index 30e5ab4..0000000
--- a/src/user/lib/fs/misc.c
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <camellia/compat.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-
-void forward_open(hid_t reqh, const char *path, long len, int flags) {
-	// TODO use threads
-	// TODO solve for more complex cases, e.g. fs_union
-	/* done in a separate thread/process because open() can block,
-	 * but that should only hold the caller back, and not the fs driver.
-	 *
-	 * for example, running `httpd` in one term would prevent you from doing
-	 * basically anything on the second term, because fs_dirinject would be
-	 * stuck on open()ing the socket */
-	if (!_sys_fork(FORK_NOREAP, NULL)) {
-		_sys_fs_respond(reqh, NULL, _sys_open(path, len, flags), FSR_DELEGATE);
-		exit(0);
-	}
-	close(reqh);
-}
-
-void fs_passthru(const char *prefix) {
-	const size_t buflen = 1024;
-	char *buf = malloc(buflen);
-	int prefix_len = prefix ? strlen(prefix) : 0;
-	if (!buf) exit(1);
-
-	for (;;) {
-		struct ufs_request res;
-		hid_t reqh = _sys_fs_wait(buf, buflen, &res);
-		if (reqh < 0) break;
-		switch (res.op) {
-			case VFSOP_OPEN:
-				if (prefix) {
-					if (prefix_len + res.len > buflen) {
-						_sys_fs_respond(reqh, NULL, -1, 0);
-						break;
-					}
-
-					memmove(buf + prefix_len, buf, res.len);
-					memcpy(buf, prefix, prefix_len);
-					res.len += prefix_len;
-				}
-				forward_open(reqh, buf, res.len, res.flags);
-				break;
-
-			default:
-				_sys_fs_respond(reqh, NULL, -1, 0);
-				break;
-		}
-	}
-	exit(0);
-}
-
-void fs_union(const char **list) {
-	struct ufs_request res;
-
-	/* the buffer is split into two halves:
-	 *  the second one is filled out with the path by fs_wait
-	 *  the first one is used for the prepended paths */
-	const size_t buflen = 1024;
-	const size_t prelen = 512;
-	const size_t postlen = buflen - prelen;
-	char *pre = malloc(buflen);
-	char *post = pre + prelen;
-	long ret;
-	struct dirbuild db;
-	if (!pre) exit(1);
-
-	while (!c0_fs_wait(post, postlen, &res)) {
-		switch (res.op) {
-			case VFSOP_OPEN:
-				if (res.len == 1) { /* root directory */
-					c0_fs_respond(NULL, 0, 0);
-					break;
-				}
-
-				ret = -1;
-				for (size_t i = 0; ret < 0 && list[i]; i++) {
-					const char *prefix = list[i];
-					size_t prefixlen = strlen(prefix); // TODO cache
-					if (prefixlen > prelen) continue;
-					char *path = post - prefixlen;
-					memcpy(path, prefix, prefixlen);
-
-					ret = _sys_open(path, prefixlen + res.len, res.flags);
-
-					post[res.len] = '\0';
-				}
-				if (ret < 0) ret = -1;
-				c0_fs_respond(NULL, ret, FSR_DELEGATE);
-				break;
-
-		case VFSOP_READ:
-		case VFSOP_GETSIZE:
-			if (res.capacity > buflen)
-				res.capacity = buflen;
-			bool end = false;
-			char *target = res.op == VFSOP_READ ? pre : NULL;
-			dir_start(&db, res.offset, target, res.capacity);
-			for (size_t i = 0; !end && list[i]; i++) {
-				const char *prefix = list[i];
-				size_t prefixlen = strlen(prefix);
-				// TODO only open the directories once
-				// TODO ensure trailing slash
-				hid_t h = _sys_open(prefix, prefixlen, OPEN_READ);
-				if (h < 0) continue;
-				end = end || dir_append_from(&db, h);
-				_sys_close(h);
-			}
-			c0_fs_respond(target, dir_finish(&db), 0);
-			break;
-
-			default:
-				c0_fs_respond(NULL, -1, 0);
-				break;
-		}
-	}
-	exit(0);
-}
-
-hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req) {
-	hid_t reqh;
-	for (;;) {
-		reqh = _sys_fs_wait(buf, len, req);
-		if (reqh < 0) break;
-		if (req->op == VFSOP_OPEN) {
-			if (req->len == len) {
-				_sys_fs_respond(reqh, NULL, -ENAMETOOLONG, 0);
-				continue;
-			}
-			buf[req->len] = '\0';
-			// TODO ensure passed paths don't have null bytes in them in the kernel
-		}
-		break;
-	}
-	return reqh;
-}
-
-int mount_at(const char *path) {
-	hid_t h;
-	int ret = _sys_fork(FORK_NEWFS, &h);
-	if (ret == 0) {
-		_klogf("%s: impl", path);
-		setproctitle("%s", path);
-	} else if (ret > 0) {
-		_sys_mount(h, path, strlen(path));
-		close(h);
-	} else {
-		_sys_mount(HANDLE_NULLFS, path, strlen(path));
-	}
-	return ret;
-}
diff --git a/src/user/lib/fs/whitelist.c b/src/user/lib/fs/whitelist.c
deleted file mode 100644
index 54a79c3..0000000
--- a/src/user/lib/fs/whitelist.c
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-
-static int dir_seglen2(const char *path, size_t len) {
-	/* returns the length of the first segment of the path, including the trailing / (if any). */
-	for (size_t i = 0; i < len; i++) {
-		if (path[i] == '/')
-			return i + 1;
-	}
-	return len;
-}
-
-/** @return the length of the path w/o suffixes */
-static size_t suffix_parse(const char *path, size_t len, bool *ro_ptr) {
-	bool ro = false;
-	if (len >= 3 && !memcmp(path + len - 3, ":ro", 3)) {
-		ro = true;
-		len -= 3;
-	}
-	if (ro_ptr) *ro_ptr = ro;
-	return len;
-}
-
-/** Check if a path is a prefix of another path. */
-// TODO move to libc; tests
-static bool prefix_match(const char *prefix, size_t plen, const char *full, size_t flen) {
-	if (flen < plen) return false;
-	if (flen == plen)
-		return memcmp(full, prefix, flen) == 0;
-	return plen >= 1
-		&& prefix[plen - 1] == '/' /* prefixes must point to one of the parent directories */
-		&& memcmp(full, prefix, plen) == 0;
-}
-
-void fs_whitelist(const char **whitelist) {
-	const size_t buflen = 1024;
-	char *buf = malloc(buflen);
-	if (!buf) exit(1);
-	for (;;) {
-		struct ufs_request res;
-		hid_t reqh = _sys_fs_wait(buf, buflen, &res);
-		if (reqh < 0) break;
-
-		char *ipath = res.id; /* the path of the open()ed directory */
-
-		switch (res.op) {
-			case VFSOP_OPEN: {
-				bool error = false;
-				bool passthru = false;
-				bool inject = false;
-
-				for (const char **entry = whitelist; *entry; entry++) {
-					bool ro = false;
-					size_t entry_len = suffix_parse(*entry, strlen(*entry), &ro);
-					/* If *entry is a prefix of the opened path, pass the open() through. */
-					if (prefix_match(*entry, entry_len, buf, res.len)) {
-						passthru = true;
-						if (ro && OPEN_WRITEABLE(res.flags))
-							error = true;
-						break;
-					}
-					/* If the path is a prefix of *entry, we might need to inject a directory. */
-					if (prefix_match(buf, res.len, *entry, entry_len)) {
-						inject = true;
-					}
-				}
-				if (error) {
-					_sys_fs_respond(reqh, NULL, -EACCES, 0);
-				} else if (passthru) {
-					forward_open(reqh, buf, res.len, res.flags);
-				} else if (inject) {
-					// TODO all the inject points could be precomputed
-					ipath = malloc(res.len + 1);
-					memcpy(ipath, buf, res.len);
-					ipath[res.len] = '\0';
-					_sys_fs_respond(reqh, ipath, 0, 0);
-				} else {
-					_sys_fs_respond(reqh, NULL, -1, 0);
-				}
-				break;
-			}
-			case VFSOP_READ:
-			case VFSOP_GETSIZE: {
-				struct dirbuild db;
-				size_t ilen = strlen(ipath);
-				char *target = res.op == VFSOP_READ ? buf : NULL;
-				dir_start(&db, res.offset, target, buflen);
-				for (const char **entry = whitelist; *entry; entry++) {
-					// TODO could be precomputed too
-					size_t elen = suffix_parse(*entry, strlen(*entry), NULL);
-					if (ilen < elen && !memcmp(ipath, *entry, ilen))
-						dir_appendl(&db, *entry + ilen, dir_seglen2(*entry + ilen, elen - ilen));
-				}
-				_sys_fs_respond(reqh, target, dir_finish(&db), 0);
-				break;
-			}
-			case VFSOP_CLOSE: {
-				free(ipath);
-				_sys_fs_respond(reqh, NULL, 0, 0);
-				break;
-			}
-			default: {
-				_sys_fs_respond(reqh, NULL, -1, 0);
-				break;
-			}
-		}
-	}
-	exit(0);
-}
diff --git a/src/user/lib/include/__errno.h b/src/user/lib/include/__errno.h
deleted file mode 100644
index 7551ce0..0000000
--- a/src/user/lib/include/__errno.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* generated by awk */
-#ifdef E
-E(  1, "EGENERIC unknown error")
-E(  2, "EFAULT")
-E(  3, "EBADF bad file descriptor")
-E(  4, "EINVAL")
-E(  5, "ENOSYS unsupported")
-E(  6, "ERANGE")
-E(  7, "ENOMEM")
-E(  8, "ENOENT")
-E(  9, "ENOTEMPTY")
-E( 10, "EACCES")
-E( 11, "EMFILE all file descriptors taken")
-E( 12, "ECONNRESET")
-E( 13, "EPIPE")
-E( 14, "ECHILD")
-E(200, "EISDIR")
-E(201, "ENAMETOOLONG")
-E(202, "ENOTDIR")
-E(203, "ELOOP")
-E(204, "ENOEXEC")
-E(205, "EINTR")
-E(206, "EWOULDBLOCK")
-E(207, "EEXIST")
-E(208, "EAGAIN")
-#endif
diff --git a/src/user/lib/include/__errno.h.awk b/src/user/lib/include/__errno.h.awk
deleted file mode 100644
index 6232835..0000000
--- a/src/user/lib/include/__errno.h.awk
+++ /dev/null
@@ -1,20 +0,0 @@
-BEGIN {
-	print "/* generated by awk */";
-	print "#ifdef E";
-}
-
-END {
-	print "#endif";
-}
-
-/#define/ {
-	comment = $2;
-	num = $3;
-	# extract the comment, if present
-	if (index($0, "/*")) {
-		sub(/[^/]*\/\*/, "");
-		sub(/ *\*\//, "");
-		comment = comment $0;
-	}
-	printf "E(%3s, \"%s\")\n", num, comment;
-}
diff --git a/src/user/lib/include/_proc.h b/src/user/lib/include/_proc.h
deleted file mode 100644
index 5f9c321..0000000
--- a/src/user/lib/include/_proc.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-struct _psdata {
-	/* Description of the process, see setprogname.
-	 * Assumed to be null terminated. */
-	char desc[1024];
-
-	/* Base offset where the executable was loaded. */
-	void *base;
-};
-
-/* First allocated in bootstrap.
- * Freed on every exec(), just to be immediately reallocated by _start2(). */
-static struct _psdata *const _psdata_loc = (void*)0x10000;
diff --git a/src/user/lib/include/alloca.h b/src/user/lib/include/alloca.h
deleted file mode 100644
index 9c7641c..0000000
--- a/src/user/lib/include/alloca.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-#include <stddef.h>
-void *alloca(size_t size);
diff --git a/src/user/lib/include/bits/file.h b/src/user/lib/include/bits/file.h
deleted file mode 100644
index 63a31c4..0000000
--- a/src/user/lib/include/bits/file.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#pragma once
-typedef struct _LIBC_FILE FILE;
diff --git a/src/user/lib/include/bits/panic.h b/src/user/lib/include/bits/panic.h
deleted file mode 100644
index 91aec5f..0000000
--- a/src/user/lib/include/bits/panic.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-#include <stdio.h>
-#include <stdlib.h>
-
-#define __libc_panic(...) do { fprintf(stderr, "__libc_panic @ %s:", __func__); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); abort(); } while (0)
diff --git a/src/user/lib/include/camellia.h b/src/user/lib/include/camellia.h
deleted file mode 100644
index 2e4998b..0000000
--- a/src/user/lib/include/camellia.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-#include <camellia/flags.h>
-#include <camellia/types.h>
-
-hid_t camellia_open(const char *path, int flags);
diff --git a/src/user/lib/include/camellia/compat.h b/src/user/lib/include/camellia/compat.h
deleted file mode 100644
index a7c6f1f..0000000
--- a/src/user/lib/include/camellia/compat.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-
-/* c0 - fs_wait returning a handle */
-long c0_fs_wait(char *buf, long len, struct ufs_request *res);
-long c0_fs_respond(void *buf, long ret, int flags);
diff --git a/src/user/lib/include/camellia/fs/dir.h b/src/user/lib/include/camellia/fs/dir.h
deleted file mode 100644
index d34a652..0000000
--- a/src/user/lib/include/camellia/fs/dir.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-#include <stdbool.h>
-#include <stddef.h>
-
-struct dirbuild {
-	long offset;
-	char *buf;
-	long bpos, blen;
-	long error;
-};
-
-void dir_start(struct dirbuild *db, long offset, char *buf, size_t buflen);
-bool dir_append(struct dirbuild *db, const char *name);
-bool dir_appendl(struct dirbuild *db, const char *name, size_t len);
-bool dir_append_from(struct dirbuild *db, hid_t h);
-long dir_finish(struct dirbuild *db);
diff --git a/src/user/lib/include/camellia/fs/misc.h b/src/user/lib/include/camellia/fs/misc.h
deleted file mode 100644
index 301c604..0000000
--- a/src/user/lib/include/camellia/fs/misc.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-#include <stdbool.h>
-#include <stdlib.h>
-
-void forward_open(hid_t reqh, const char *path, long len, int flags);
-
-void fs_passthru(const char *prefix);
-void fs_whitelist(const char **list);
-void fs_union(const char **list);
-
-void fs_dirinject(const char *path);
-void fs_dirinject2(const char *injects[]);
-
-int mount_at(const char *path);
-
-// TODO separate fs drivers and wrappers around syscalls
-
-/** like _sys_fs_wait, but ensures *buf is a null terminated string on VFSOP_OPEN */
-hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req);
-
-/** Mounts something and injects its path into the fs */
-#define MOUNT_AT(path) for (; mount_at(path) == 0; exit(1))
diff --git a/src/user/lib/include/ctype.h b/src/user/lib/include/ctype.h
deleted file mode 100644
index 1ebb111..0000000
--- a/src/user/lib/include/ctype.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-int isalnum(int c);
-int isalpha(int c);
-int iscntrl(int c);
-int isdigit(int c);
-int isgraph(int c);
-int islower(int c);
-int isprint(int c);
-int ispunct(int c);
-int isspace(int c);
-int isupper(int c);
-int isxdigit(int c);
-
-int tolower(int c);
-int toupper(int c);
diff --git a/src/user/lib/include/dirent.h b/src/user/lib/include/dirent.h
deleted file mode 100644
index 7c419d7..0000000
--- a/src/user/lib/include/dirent.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-#include <stdio.h>
-
-struct dirent {
-	ino_t d_ino;
-	char d_name[256]; /* NAME_MAX + 1 */
-};
-
-typedef struct {
-	FILE *fp;
-	struct dirent dent;
-} DIR;
-
-DIR *opendir(const char *name);
-int closedir(DIR *dir);
-struct dirent *readdir(DIR *dir);
diff --git a/src/user/lib/include/draw.h b/src/user/lib/include/draw.h
deleted file mode 100644
index 5e614be..0000000
--- a/src/user/lib/include/draw.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-#include <stddef.h>
-#include <stdint.h>
-
-struct framebuf {
-	size_t len, width, height, pitch;
-	uint8_t bpp;
-	char *b;
-
-	hid_t fd;
-};
-
-struct rect { uint32_t x1, y1, x2, y2; };
-void dirty_reset(struct rect *d);
-void dirty_mark(struct rect *d, uint32_t x, uint32_t y);
-void dirty_flush(struct rect *d, struct framebuf *fb);
-
-int fb_setup(struct framebuf *fb, const char *base);
-int fb_anon(struct framebuf *fb, size_t w, size_t h);
-uint32_t *fb_pixel(struct framebuf *fb, uint32_t x, uint32_t y);
-void fb_cpy(
-	struct framebuf *dest, const struct framebuf *src,
-	size_t xd, size_t yd, size_t xs, size_t ys, size_t w, size_t h);
diff --git a/src/user/lib/include/elfload.h b/src/user/lib/include/elfload.h
deleted file mode 100644
index 825f765..0000000
--- a/src/user/lib/include/elfload.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include <bits/file.h>
-
-struct execdata {
-	int argc;
-	char **argv, **envp;
-	char *cwd;
-};
-
-void elf_execf(FILE *f, char **argv, char **envp);
-void elf_exec(void *base, char **argv, char **envp);
-void *elf_partialexec(void *elf); /* returns pointer to entry point */
-
-void elf_selfreloc(void); // elfreloc.c
diff --git a/src/user/lib/include/err.h b/src/user/lib/include/err.h
deleted file mode 100644
index 6b63c6c..0000000
--- a/src/user/lib/include/err.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include <stdarg.h>
-
-_Noreturn void err(int ret, const char *fmt, ...);
-_Noreturn void errx(int ret, const char *fmt, ...);
-void warn(const char *fmt, ...);
-void warnx(const char *fmt, ...);
-
-void vwarn(const char *fmt, va_list args);
-void vwarnx(const char *fmt, va_list args);
diff --git a/src/user/lib/include/errno.h b/src/user/lib/include/errno.h
deleted file mode 100644
index 6686a01..0000000
--- a/src/user/lib/include/errno.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-#include <camellia/errno.h>
-extern int errno;
diff --git a/src/user/lib/include/esemaphore.h b/src/user/lib/include/esemaphore.h
deleted file mode 100644
index 9cc85e0..0000000
--- a/src/user/lib/include/esemaphore.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-
-struct evil_sem {
-	hid_t wait, signal;
-};
-
-void esem_signal(struct evil_sem *sem);
-void esem_wait(struct evil_sem *sem);
-
-struct evil_sem *esem_new(int value);
-void esem_free(struct evil_sem *sem);
diff --git a/src/user/lib/include/fcntl.h b/src/user/lib/include/fcntl.h
deleted file mode 100644
index 6338d1f..0000000
--- a/src/user/lib/include/fcntl.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#define F_SETFL 1
-#define F_GETFL 2
-#define F_DUPFD 3
-#define F_SETFD 4
-
-#define FD_CLOEXEC 1
-
-#define O_APPEND 0
-#define O_CREAT 0
-#define O_EXCL 0
-#define O_NONBLOCK 0
-#define O_RDONLY 0
-#define O_RDWR 0
-#define O_TRUNC 0
-#define O_WRONLY 0
-
-#define R_OK 1
-#define W_OK 2
-#define X_OK 4
-
-/* it can either take an additonal mode_t argument or none */
-int open(const char *path, int flags, ...);
-int fcntl(int fd, int cmd, ...);
diff --git a/src/user/lib/include/ftw.h b/src/user/lib/include/ftw.h
deleted file mode 100644
index 6dc8132..0000000
--- a/src/user/lib/include/ftw.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-#include <sys/stat.h>
-
-int ftw(const char *dirpath,
-		int (*fn)(const char *fpath, const struct stat *sb, int typeflag),
-		int nopenfd);
diff --git a/src/user/lib/include/getopt.h b/src/user/lib/include/getopt.h
deleted file mode 120000
index 4890ceb..0000000
--- a/src/user/lib/include/getopt.h
+++ /dev/null
@@ -1 +0,0 @@
-../vendor/getopt/getopt.h
\ No newline at end of file
diff --git a/src/user/lib/include/grp.h b/src/user/lib/include/grp.h
deleted file mode 100644
index e7b99c9..0000000
--- a/src/user/lib/include/grp.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-struct group {
-	char *gr_name;
-	char *gr_passwd;
-	gid_t gr_gid;
-	char **gr_mem;
-};
-
-struct group *getgrgid(gid_t gid);
diff --git a/src/user/lib/include/inttypes.h b/src/user/lib/include/inttypes.h
deleted file mode 100644
index 9a6118b..0000000
--- a/src/user/lib/include/inttypes.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <stdint.h>
diff --git a/src/user/lib/include/limits.h b/src/user/lib/include/limits.h
deleted file mode 100644
index 972553f..0000000
--- a/src/user/lib/include/limits.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-#include <camellia/path.h> // just for PATH_MAX
-// #include_next <limits.h>
-
-#define _POSIX2_RE_DUP_MAX 255
-#define NAME_MAX 255
diff --git a/src/user/lib/include/locale.h b/src/user/lib/include/locale.h
deleted file mode 100644
index 1221375..0000000
--- a/src/user/lib/include/locale.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#pragma once
-#include <limits.h>
-
-#define LC_ALL 0
-#define LC_COLLATE 1
-#define LC_CTYPE 2
-#define LC_MESSAGES 3
-#define LC_MONETARY 4
-#define LC_NUMERIC 5
-#define LC_TIME 6
-
-struct lconv {
-	char *decimal_point;
-	char *thousands_sep;
-	char *grouping;
-	char *mon_decimal_point;
-	char *mon_thousands_sep;
-	char *mon_grouping;
-	char *positive_sign;
-	char *negative_sign;
-	char *currency_symbol;
-	char frac_digits;
-	char p_cs_precedes;
-	char n_cs_precedes;
-	char p_sep_by_space;
-	char n_sep_by_space;
-	char p_sign_posn;
-	char n_sign_posn;
-	char *int_curr_symbol;
-	char int_frac_digits;
-	char int_p_cs_precedes;
-	char int_n_cs_precedes;
-	char int_p_sep_by_space;
-	char int_n_sep_by_space;
-	char int_p_sign_posn;
-	char int_n_sign_posn;
-};
-
-static inline struct lconv *localeconv(void) {
-	/* per Linux's lconv(3) */
-	static struct lconv locale = (struct lconv){
-		.decimal_point = ".",
-		.thousands_sep = "",
-		.grouping = "",
-		.mon_decimal_point = "",
-		.mon_thousands_sep = "",
-		.mon_grouping = "",
-		.positive_sign = "",
-		.negative_sign = "",
-		.currency_symbol = "",
-		.frac_digits = CHAR_MAX,
-		.p_cs_precedes = CHAR_MAX,
-		.n_cs_precedes = CHAR_MAX,
-		.p_sep_by_space = CHAR_MAX,
-		.n_sep_by_space = CHAR_MAX,
-		.p_sign_posn = CHAR_MAX,
-		.n_sign_posn = CHAR_MAX,
-		.int_curr_symbol = "",
-		.int_frac_digits = CHAR_MAX,
-		.int_p_cs_precedes = CHAR_MAX,
-		.int_n_cs_precedes = CHAR_MAX,
-		.int_p_sep_by_space = CHAR_MAX,
-		.int_n_sep_by_space = CHAR_MAX,
-		.int_p_sign_posn = CHAR_MAX,
-		.int_n_sign_posn = CHAR_MAX,
-	};
-	return &locale;
-}
-
-static inline char *setlocale(int category, const char *locale) {
-	(void)category; (void)locale;
-	return NULL;
-}
diff --git a/src/user/lib/include/malloc.h b/src/user/lib/include/malloc.h
deleted file mode 120000
index 80b9bf5..0000000
--- a/src/user/lib/include/malloc.h
+++ /dev/null
@@ -1 +0,0 @@
-../vendor/dlmalloc/malloc.h
\ No newline at end of file
diff --git a/src/user/lib/include/math.h b/src/user/lib/include/math.h
deleted file mode 100644
index 1aec564..0000000
--- a/src/user/lib/include/math.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#define INFINITY __builtin_inff()
-#define HUGE_VAL ((double)INFINITY)
-
-double acos(double x);
-double asin(double x);
-double atan2(double x, double y);
-double cos(double x);
-double cosh(double x);
-double sin(double x);
-double sinh(double x);
-double tan(double x);
-double tanh(double x);
-
-double fabs(double x);
-double floor(double x);
-double ceil(double x);
-double log(double x);
-double log2(double x);
-double log10(double x);
-double exp(double x);
-double fmod(double x, double y);
-double frexp(double num, int *exp);
-double ldexp(double x, int exp);
-double pow(double x, double y);
-double sqrt(double x);
diff --git a/src/user/lib/include/pwd.h b/src/user/lib/include/pwd.h
deleted file mode 100644
index 6721ca2..0000000
--- a/src/user/lib/include/pwd.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-struct passwd {
-	char *pw_name;
-	char *pw_passwd;
-	uid_t pw_uid;
-	gid_t pw_gid;
-	char *pw_gecos;
-	char *pw_dir;
-	char *pw_shell;
-};
-
-struct passwd *getpwuid(uid_t uid);
diff --git a/src/user/lib/include/setjmp.h b/src/user/lib/include/setjmp.h
deleted file mode 100644
index 6d05d79..0000000
--- a/src/user/lib/include/setjmp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-
-typedef uint64_t jmp_buf[8]; /* rbx, rsp, rbp, r12, r13, r14, r15, rip */
-typedef char sigjmp_buf[1];
-
-int setjmp(jmp_buf env);
-_Noreturn void longjmp(jmp_buf env, int val);
-
-static inline int sigsetjmp(sigjmp_buf env, int savemask) {
-	(void)env; (void)savemask;
-	return 0;
-}
-
-static inline _Noreturn void siglongjmp(sigjmp_buf env, int val) {
-	(void)env; (void)val;
-	__libc_panic("unimplemented");
-}
diff --git a/src/user/lib/include/signal.h b/src/user/lib/include/signal.h
deleted file mode 100644
index 012481e..0000000
--- a/src/user/lib/include/signal.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-#include <sys/types.h>
-#include <errno.h> // only for ENOSYS
-
-#define SIGHUP 1
-#define SIGINT 2
-#define SIGQUIT 3
-#define SIGILL 4
-#define SIGTRAP 5
-#define SIGABRT 6
-#define SIGFPE 8
-#define SIGKILL 9
-#define SIGSEGV 11
-#define SIGPIPE 13
-#define SIGALRM 14
-#define SIGTERM 15
-
-#define SIGCONT 16
-#define SIGPIPE 17
-#define SIGTSTP 18
-#define SIGTTIN 19
-#define SIGTTOU 20
-#define SIGWINCH 21
-#define SIGCHLD 22
-
-#define NSIG 32
-
-#define SIG_DFL 0
-#define SIG_ERR 0
-#define SIG_IGN 0
-#define SIG_SETMASK 0
-
-typedef int sig_atomic_t;
-typedef struct {} sigset_t;
-typedef struct {} siginfo_t;
-extern const char *const sys_siglist[];
-
-struct sigaction {
-	void (*sa_handler)(int);
-	void (*sa_sigaction)(int, siginfo_t *, void *);
-	sigset_t sa_mask;
-	int sa_flags;
-	void (*sa_restorer)(void);
-};
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact);
-int sigemptyset(sigset_t *set);
-int sigfillset(sigset_t *set);
-int sigprocmask(int how, const sigset_t *set, const sigset_t *oldset);
-int sigsuspend(const sigset_t *mask);
-int signal(int sig, void (*func)(int));
-int kill(pid_t pid, int sig);
-int raise(int sig);
diff --git a/src/user/lib/include/stdio.h b/src/user/lib/include/stdio.h
deleted file mode 100644
index 48d5058..0000000
--- a/src/user/lib/include/stdio.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#pragma once
-#include <bits/file.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#define EOF (-1)
-#define STDIN_FILENO 0
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-
-#define SEEK_SET 1
-#define SEEK_CUR 2
-#define SEEK_END 3
-
-#define _IONBF 0
-#define _IOFBF 1
-#define _IOLBF 2
-
-#define BUFSIZ 4096
-
-/* stop fread() from trying to fill the entire buffer before returning
- * i.e. it will call _sys_read() exactly once */
-#define FEXT_NOFILL 1
-
-int printf(const char *restrict fmt, ...);
-int fprintf(FILE *restrict f, const char *restrict fmt, ...);
-
-int sprintf(char *restrict s, const char *restrict fmt, ...);
-
-int vprintf(const char *restrict fmt, va_list ap);
-int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap);
-
-int _klogf(const char *fmt, ...); // for kernel debugging only
-
-
-extern FILE *const stdin, *const stdout, *const stderr;
-
-FILE *fopen(const char *path, const char *mode);
-FILE *freopen(const char *path, const char *mode, FILE *);
-FILE *fdopen(int fd, const char *mode);
-FILE *file_clone(const FILE *, const char *mode);
-FILE *popen(const char *cmd, const char *mode);
-int pclose(FILE *f);
-FILE *tmpfile(void);
-
-int fextflags(FILE *, int extflags);
-int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size);
-int fclose(FILE *);
-int fflush(FILE *f);
-
-size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict);
-size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict);
-int fputs(const char *s, FILE *f);
-char *fgets(char *buf, int size, FILE *f);
-int fgetc(FILE *f);
-int getc(FILE *f);
-int fputc(int c, FILE *f);
-int putc(int c, FILE *f);
-int ungetc(int c, FILE *f);
-
-int fseek(FILE *f, long offset, int whence);
-int fseeko(FILE *f, off_t offset, int whence);
-long ftell(FILE *f);
-off_t ftello(FILE *f);
-
-int feof(FILE *);
-int ferror(FILE *);
-void clearerr(FILE *f);
-
-void perror(const char *s);
-int puts(const char *s);
-int getchar(void);
-int putchar(int c);
-
-off_t lseek(int fd, off_t off, int whence);
-
-int remove(const char *path);
-int rename(const char *old, const char *new);
-
-#define L_tmpnam (5 + 16 + 1)
-char *tmpnam(char *s);
-
-int sscanf(const char *restrict s, const char *restrict format, ...);
diff --git a/src/user/lib/include/stdlib.h b/src/user/lib/include/stdlib.h
deleted file mode 100644
index ee9d179..0000000
--- a/src/user/lib/include/stdlib.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-#include <stddef.h>
-#include <stdlib.h>
-
-#ifndef NO_MALLOC_H
-#include <malloc.h>
-#endif
-
-#define EXIT_SUCCESS 0
-#define EXIT_FAILURE 1
-
-_Noreturn void abort(void);
-_Noreturn void exit(int);
-
-const char *getprogname(void);
-void setprogname(const char *progname);
-void setproctitle(const char *fmt, ...);
-
-int mkstemp(char *template);
-char *getenv(const char *name);
-int system(const char *cmd);
-
-int abs(int i);
-
-int atoi(const char *s);
-double atof(const char *s);
-
-long strtol(const char *restrict s, char **restrict end, int base);
-long long strtoll(const char *restrict s, char **restrict end, int base);
-unsigned long strtoul(const char *restrict s, char **restrict end, int base);
-unsigned long long strtoull(const char *restrict s, char **restrict end, int base);
-double strtod(const char *restrict s, char **restrict end);
-
-void qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *a, const void *b));
diff --git a/src/user/lib/include/string.h b/src/user/lib/include/string.h
deleted file mode 100644
index 78bed9b..0000000
--- a/src/user/lib/include/string.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-#include <shared/mem.h>
-#include <strings.h> /* work around bad include in dash */
-
-char *strchr(const char *s, int c);
-char *strrchr(const char *s, int c);
-
-size_t strspn(const char *s, const char *accept);
-size_t strcspn(const char *s, const char *reject);
-char *strpbrk(const char *s1, const char *s2);
-
-char *strtok(char *restrict s, const char *restrict sep);
-char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state);
-
-int strncmp(const char *s1, const char *s2, size_t n);
-int strcoll(const char *s1, const char *s2);
-
-char *strstr(const char *s1, const char *s2);
-
-char *strcpy(char *restrict s1, const char *restrict s2);
-char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
-char *stpncpy(char *restrict dst, const char *restrict src, size_t n);
-char *strdup(const char *s);
-
-char *strerror(int errnum);
diff --git a/src/user/lib/include/strings.h b/src/user/lib/include/strings.h
deleted file mode 100644
index d0abc47..0000000
--- a/src/user/lib/include/strings.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-#include <stddef.h>
-
-int strcasecmp(const char *s1, const char *s2);
-int strncasecmp(const char *s1, const char *s2, size_t n);
diff --git a/src/user/lib/include/sys/ioctl.h b/src/user/lib/include/sys/ioctl.h
deleted file mode 100644
index 708bc3f..0000000
--- a/src/user/lib/include/sys/ioctl.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include <errno.h> // only for ENOSYS
-
-#define TIOCGWINSZ 0
-struct winsize {
-	int ws_row, ws_col;
-};
-
-static inline int ioctl(int fd, int req, ...) {
-	(void)fd; (void)req;
-	errno = ENOSYS;
-	return -1;
-}
diff --git a/src/user/lib/include/sys/mman.h b/src/user/lib/include/sys/mman.h
deleted file mode 100644
index 074ebe2..0000000
--- a/src/user/lib/include/sys/mman.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include <camellia/flags.h>
-#include <sys/types.h>
-
-#define MMAP_UNSUPPORTED 0xFFFF
-
-#define PROT_EXEC 1
-#define PROT_NONE MMAP_UNSUPPORTED
-#define PROT_READ 1
-#define PROT_WRITE 1
-
-#define MAP_FIXED MMAP_UNSUPPORTED
-#define MAP_PRIVATE 0
-#define MAP_SHARED MMAP_UNSUPPORTED
-#define MAP_ANONYMOUS 1
-
-void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off);
-int munmap(void *addr, size_t len);
diff --git a/src/user/lib/include/sys/param.h b/src/user/lib/include/sys/param.h
deleted file mode 100644
index e6c9d6f..0000000
--- a/src/user/lib/include/sys/param.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#define MIN(a, b) ((a)<(b) ? (a):(b))
-#define MAX(a, b) ((a)<(b) ? (b):(a))
diff --git a/src/user/lib/include/sys/resource.h b/src/user/lib/include/sys/resource.h
deleted file mode 100644
index 4582ce0..0000000
--- a/src/user/lib/include/sys/resource.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#pragma once
-struct rusage {};
diff --git a/src/user/lib/include/sys/stat.h b/src/user/lib/include/sys/stat.h
deleted file mode 100644
index 343db55..0000000
--- a/src/user/lib/include/sys/stat.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h> // struct timespec
-#include <errno.h> // only for ENOSYS
-
-struct stat {
-	dev_t st_dev;
-	ino_t st_ino;
-	mode_t st_mode;
-	nlink_t st_nlink;
-	uid_t st_uid;
-	gid_t st_gid;
-	dev_t st_rdev;
-	off_t st_size;
-	blksize_t st_blksize;
-	blkcnt_t st_blocks;
-
-	struct timespec st_atim;
-	struct timespec st_mtim;
-	struct timespec st_ctim;
-
-#define st_atime st_atim.tv_sec
-#define st_mtime st_mtim.tv_sec
-#define st_ctime st_ctim.tv_sec
-};
-
-#define S_IFMT  0170000
-#define S_IFSOCK 0140000
-#define S_IFLNK 0120000
-#define S_IFREG 0100000
-#define S_IFBLK 0060000
-#define S_IFDIR 0040000
-#define S_IFCHR 0020000
-#define S_IFIFO 0010000
-#define S_ISUID 04000
-#define S_ISGID 02000
-#define S_ISVTX 01000
-
-/* inode(7) */
-#define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
-#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
-#define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
-#define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
-#define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
-#define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
-#define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
-
-int fstat(int fd, struct stat *sb);
-int stat(const char *restrict path, struct stat *restrict sb);
-int lstat(const char *restrict path, struct stat *restrict sb);
-int mkdir(const char *path, mode_t mode);
-
-static inline mode_t umask(mode_t mask) {
-	(void)mask;
-	__libc_panic("unimplemented");
-}
-
-static inline int chmod(const char *path, mode_t mode) {
-	(void)path; (void)mode;
-	errno = ENOSYS;
-	return -1;
-}
-
-static inline int mknod(const char *path, mode_t mode, dev_t dev) {
-	(void)path; (void)mode; (void)dev;
-	errno = ENOSYS;
-	return -1;
-}
diff --git a/src/user/lib/include/sys/sysmacros.h b/src/user/lib/include/sys/sysmacros.h
deleted file mode 100644
index 30e0efd..0000000
--- a/src/user/lib/include/sys/sysmacros.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#define makedev(maj, min) 0
-#define major(x) 0
-#define minor(x) 0
diff --git a/src/user/lib/include/sys/time.h b/src/user/lib/include/sys/time.h
deleted file mode 100644
index e69de29..0000000
diff --git a/src/user/lib/include/sys/times.h b/src/user/lib/include/sys/times.h
deleted file mode 100644
index 4a8d3ef..0000000
--- a/src/user/lib/include/sys/times.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-
-struct tms {
-	clock_t tms_utime;
-	clock_t tms_stime;
-	clock_t tms_cutime;
-	clock_t tms_cstime;
-};
-
-static inline clock_t times(struct tms *buf) {
-	__libc_panic("unimplemented");
-}
diff --git a/src/user/lib/include/sys/types.h b/src/user/lib/include/sys/types.h
deleted file mode 100644
index faf656a..0000000
--- a/src/user/lib/include/sys/types.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include <stddef.h>
-#include <stdint.h>
-
-typedef long long off_t;
-typedef int64_t time_t;
-typedef uint64_t clock_t;
-typedef int mode_t;
-
-typedef int dev_t;
-typedef int ino_t;
-typedef int mode_t;
-typedef int nlink_t;
-typedef int uid_t;
-typedef int gid_t;
-typedef int blksize_t;
-typedef int blkcnt_t;
-typedef int pid_t;
diff --git a/src/user/lib/include/sys/wait.h b/src/user/lib/include/sys/wait.h
deleted file mode 100644
index cff407e..0000000
--- a/src/user/lib/include/sys/wait.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-#define WIFSTOPPED(x) 0
-#define WEXITSTATUS(x) ((x)&0xFF)
-#define WIFEXITED(x) 1
-#define WSTOPSIG(x) 0
-#define WTERMSIG(x) 0
-
-#define WNOHANG 0
-#define WUNTRACED 0
-
-pid_t wait3(int *wstatus, int opts, struct rusage *rusage);
diff --git a/src/user/lib/include/termios.h b/src/user/lib/include/termios.h
deleted file mode 100644
index e69de29..0000000
diff --git a/src/user/lib/include/thread.h b/src/user/lib/include/thread.h
deleted file mode 100644
index 5a5ddc0..0000000
--- a/src/user/lib/include/thread.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-#include <stdlib.h>
-
-void thread_creates(int flags, void (*fn)(void*), void *arg, void *stack);
-
-static inline void thread_create(int flags, void (*fn)(void*), void *arg) {
-	/* error checking is for WIMPS. */
-	thread_creates(flags, fn, arg, malloc(4096) + 4096);
-}
diff --git a/src/user/lib/include/time.h b/src/user/lib/include/time.h
deleted file mode 100644
index 5d03664..0000000
--- a/src/user/lib/include/time.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-#define CLOCKS_PER_SEC 1000000
-
-struct tm {
-	int tm_sec;    /* Seconds [0,60]. */
-	int tm_min;    /* Minutes [0,59]. */
-	int tm_hour;   /* Hour [0,23]. */
-	int tm_mday;   /* Day of month [1,31]. */
-	int tm_mon;    /* Month of year [0,11]. */
-	int tm_year;   /* Years since 1900. */
-	int tm_wday;   /* Day of week [0,6] (Sunday =0). */
-	int tm_yday;   /* Day of year [0,365]. */
-	int tm_isdst;  /* Daylight Savings flag. */
-};
-
-struct timespec {
-	time_t tv_sec;
-	long long tv_nsec;
-};
-
-time_t time(time_t *tloc);
-clock_t clock(void);
-
-struct tm *gmtime(const time_t *timer);
-struct tm *localtime(const time_t *timer);
-time_t mktime(struct tm *timeptr);
-
-double difftime(time_t time1, time_t time0);
-
-size_t strftime(
-	char *restrict s, size_t maxsize,
-	const char *restrict format, const struct tm *restrict timeptr);
diff --git a/src/user/lib/include/unistd.h b/src/user/lib/include/unistd.h
deleted file mode 100644
index 005e79c..0000000
--- a/src/user/lib/include/unistd.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#pragma once
-#include <camellia/types.h> // TODO only needed because of hid_t
-#include <sys/types.h>
-#include <getopt.h>
-
-// TODO custom stdint.h, ssize_t doesn't belong here
-typedef long long ssize_t;
-
-extern char **environ;
-
-int fork(void);
-pid_t vfork(void);
-int close(hid_t h);
-_Noreturn void _exit(int);
-
-ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
-int link(const char *path1, const char *path2);
-int unlink(const char *path);
-int symlink(const char *path1, const char *path2);
-int isatty(int fd);
-
-int execv(const char *path, char *const argv[]);
-int execve(const char *path, char *const argv[], char *const envp[]);
-
-int chdir(const char *path);
-char *getcwd(char *buf, size_t size);
-
-uid_t getuid(void);
-uid_t geteuid(void);
-gid_t getgid(void);
-gid_t getegid(void);
-
-int chown(const char *path, uid_t owner, gid_t group);
-
-int setpgid(pid_t pid, pid_t pgid);
-pid_t tcgetpgrp(int fd);
-int tcsetpgrp(int fd, pid_t pgrp);
-pid_t getpgrp(void);
-pid_t getpid(void);
-pid_t getppid(void);
-
-int getgroups(int size, gid_t list[]);
-
-ssize_t read(int fd, void *buf, size_t count);
-ssize_t write(int fd, const void *buf, size_t count);
-int pipe(int pipefd[2]);
-int dup2(int oldfd, int newfd);
-
-/* Converts a relative path to an absolute one, simplifying it if possible.
- * If in == NULL - return the length of cwd. Doesn't include the trailing slash,
- *                 except for the root dir. Includes the null byte.
- * If size isn't enough to fit the path, returns the amount of bytes needed to fit
- * it, including the null byte.
- *
- * Note that some errors are only detected if *out != NULL, so you must check the return
- * value twice.
- * @return 0 on failure, length of the path otherwise */
-size_t absolutepath(char *out, const char *in, size_t size);
-
-// TODO put in an internal libc header
-void __setinitialcwd(const char *c);
-
-void intr_set(void (*fn)(void));
-void intr_default(void);
diff --git a/src/user/lib/intr.s b/src/user/lib/intr.s
deleted file mode 100644
index 008387d..0000000
--- a/src/user/lib/intr.s
+++ /dev/null
@@ -1,20 +0,0 @@
-.section .text
-.global intr_trampoline
-.type intr_trampoline, @function
-intr_trampoline:
-	push %rax
-	push %rdx
-	call *_intr(%rip)
-	pop %rdx
-	pop %rax
-	pop tmprip(%rip)
-	pop %rsp
-	jmp *tmprip(%rip)
-
-.section .bss
-tmprip:
-	.skip 8
-
-.global _intr
-_intr:
-	.skip 8
diff --git a/src/user/lib/math.c b/src/user/lib/math.c
deleted file mode 100644
index 4f8eda4..0000000
--- a/src/user/lib/math.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <math.h>
-#include <bits/panic.h>
-
-// TODO port a libm
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-double acos(double x)	{ __libc_panic("unimplemented"); }
-double asin(double x)	{ __libc_panic("unimplemented"); }
-double atan2(double x, double y)	{ __libc_panic("unimplemented"); }
-double cos(double x)	{ __libc_panic("unimplemented"); }
-double cosh(double x)	{ __libc_panic("unimplemented"); }
-double sin(double x)	{ __libc_panic("unimplemented"); }
-double sinh(double x)	{ __libc_panic("unimplemented"); }
-double tan(double x)	{ __libc_panic("unimplemented"); }
-double tanh(double x)	{ __libc_panic("unimplemented"); }
-
-double fabs(double x)	{ __libc_panic("unimplemented"); }
-double floor(double x)	{ __libc_panic("unimplemented"); }
-double ceil(double x)	{ __libc_panic("unimplemented"); }
-double log(double x)	{ __libc_panic("unimplemented"); }
-double log2(double x)	{ __libc_panic("unimplemented"); }
-double log10(double x)	{ __libc_panic("unimplemented"); }
-double exp(double x)	{ __libc_panic("unimplemented"); }
-double fmod(double x, double y)	{ __libc_panic("unimplemented"); }
-double frexp(double num, int *exp)	{ __libc_panic("unimplemented"); }
-double ldexp(double x, int exp)	{ __libc_panic("unimplemented"); }
-double pow(double x, double y)	{ __libc_panic("unimplemented"); }
-double sqrt(double x)	{ __libc_panic("unimplemented"); }
diff --git a/src/user/lib/mman.c b/src/user/lib/mman.c
deleted file mode 100644
index 32eeb2a..0000000
--- a/src/user/lib/mman.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* mmap() emulation */
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <sys/mman.h>
-
-void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) {
-	(void)fd; (void) off;
-	if ((flags & MMAP_UNSUPPORTED) == MMAP_UNSUPPORTED ||
-		(prot & MMAP_UNSUPPORTED) == MMAP_UNSUPPORTED ||
-		!(flags & MAP_ANONYMOUS))
-	{
-		errno = ENOSYS;
-		return NULL;
-	}
-
-	void *p = _sys_memflag(addr, len, MEMFLAG_FINDFREE | MEMFLAG_PRESENT);
-	if (!p) errno = ENOMEM;
-	return p;
-}
-
-int munmap(void *addr, size_t len) {
-	_sys_memflag(addr, len, 0);
-	return 0;
-}
diff --git a/src/user/lib/printf.c b/src/user/lib/printf.c
deleted file mode 100644
index ad1fd06..0000000
--- a/src/user/lib/printf.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include <camellia/syscalls.h>
-#include <shared/printf.h>
-#include <stdio.h>
-#include <string.h>
-
-
-static void backend_file(void *arg, const char *buf, size_t len) {
-	fwrite(buf, 1, len, arg);
-}
-
-int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) {
-	return __printf_internal(fmt, ap, backend_file, f);
-}
-
-
-int printf(const char *restrict fmt, ...) {
-	int ret;
-	va_list argp;
-	va_start(argp, fmt);
-	ret = vprintf(fmt, argp);
-	va_end(argp);
-	return ret;
-}
-
-int fprintf(FILE *restrict f, const char *restrict fmt, ...) {
-	int ret;
-	va_list argp;
-	va_start(argp, fmt);
-	ret = vfprintf(f, fmt, argp);
-	va_end(argp);
-	return ret;
-}
-
-int sprintf(char *restrict s, const char *restrict fmt, ...) {
-	int ret;
-	va_list argp;
-	va_start(argp, fmt);
-	ret = vsnprintf(s, ~0, fmt, argp);
-	va_end(argp);
-	return ret;
-}
-
-int vprintf(const char *restrict fmt, va_list ap) {
-	return vfprintf(stdout, fmt, ap);
-}
-
-int _klogf(const char *fmt, ...) {
-	char buf[256];
-	int ret;
-	va_list argp;
-	va_start(argp, fmt);
-	ret = vsnprintf(buf, sizeof buf, fmt, argp);
-	va_end(argp);
-	_sys_debug_klog(buf, ret);
-	return ret;
-}
diff --git a/src/user/lib/pwd.c b/src/user/lib/pwd.c
deleted file mode 100644
index d7bf2af..0000000
--- a/src/user/lib/pwd.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <grp.h>
-#include <pwd.h>
-#include <string.h>
-
-struct passwd *
-getpwuid(uid_t uid)
-{
-	static struct passwd p;
-	memset(&p, 0, sizeof p);
-	p.pw_name = "unnamed";
-	p.pw_uid = uid;
-	return &p;
-}
-
-struct group *
-getgrgid(gid_t gid)
-{
-	static struct group g;
-	memset(&g, 0, sizeof g);
-	g.gr_name = "unnamed";
-	g.gr_gid = gid;
-	return &g;
-}
diff --git a/src/user/lib/setjmp.s b/src/user/lib/setjmp.s
deleted file mode 100644
index 29292da..0000000
--- a/src/user/lib/setjmp.s
+++ /dev/null
@@ -1,39 +0,0 @@
-.section .text
-.global setjmp
-.type setjmp, @function
-// int setjmp(jmp_buf env);
-setjmp:
-	mov  %rbx,  0(%rdi)
-	mov  %rbp, 16(%rdi)
-	mov  %r12, 24(%rdi)
-	mov  %r13, 32(%rdi)
-	mov  %r14, 40(%rdi)
-	mov  %r15, 48(%rdi)
-	/* save registers as if after a ret */
-	lea 8(%rsp), %rax
-	mov %rax, 8(%rdi)
-	mov (%rsp), %rax
-	mov %rax, 56(%rdi)
-	xor %rax, %rax
-
-	mov   8(%rdi), %rsp
-	jmp *56(%rdi)
-
-	ret
-
-
-.global longjmp
-.type longjmp, @function
-// _Noreturn void longjmp(jmp_buf env, int val);
-longjmp:
-	mov %rsi, %rax
-	cmp $1, %rax /* carry set as for %rax - 1 - so, 1 only if %rax == 0 */
-	adc $0, %rax
-1:	mov   0(%rdi), %rbx
-	mov   8(%rdi), %rsp
-	mov  16(%rdi), %rbp
-	mov  24(%rdi), %r12
-	mov  32(%rdi), %r13
-	mov  40(%rdi), %r14
-	mov  48(%rdi), %r15
-	jmp *56(%rdi)
diff --git a/src/user/lib/signal.c b/src/user/lib/signal.c
deleted file mode 100644
index 3200263..0000000
--- a/src/user/lib/signal.c
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <bits/panic.h>
-#include <signal.h>
-
-const char *const sys_siglist[] = {
-	NULL,
-	"SIGHUP", /* 1 */
-	"SIGINT", /* 2 */
-	"SIGQUIT", /* 3 */
-	"SIGILL", /* 4 */
-	"SIGTRAP", /* 5 */
-	"SIGABRT", /* 6 */
-	"SIGFPE", /* 8 */
-	"SIGKILL", /* 9 */
-	"SIGSEGV", /* 11 */
-	"SIGPIPE", /* 13 */
-	"SIGALRM", /* 14 */
-	"SIGTERM", /* 15 */
-	"SIGCONT", /* 16 */
-	"SIGPIPE", /* 17 */
-	"SIGTSTP", /* 18 */
-	"SIGTTIN", /* 19 */
-	"SIGTTOU", /* 20 */
-	"SIGWINCH", /* 21 */
-	"SIGCHLD", /* 22 */
-};
-
-static struct sigaction sigaction_default = {};
-static struct sigaction *sigaction_current[] = {
-	NULL,
-	&sigaction_default, /* 1 */
-	&sigaction_default, /* 2 */
-	&sigaction_default, /* 3 */
-	&sigaction_default, /* 4 */
-	&sigaction_default, /* 5 */
-	&sigaction_default, /* 6 */
-	&sigaction_default, /* 8 */
-	&sigaction_default, /* 9 */
-	&sigaction_default, /* 11 */
-	&sigaction_default, /* 13 */
-	&sigaction_default, /* 14 */
-	&sigaction_default, /* 15 */
-	&sigaction_default, /* 16 */
-	&sigaction_default, /* 17 */
-	&sigaction_default, /* 18 */
-	&sigaction_default, /* 19 */
-	&sigaction_default, /* 20 */
-	&sigaction_default, /* 21 */
-	&sigaction_default, /* 22 */
-};
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
-	const int siglen = sizeof(sigaction_current) / sizeof(sigaction_current[0]);
-	if (sig >= siglen) {
-		return errno = EINVAL, -1;
-	}
-	if (oldact) {
-		oldact = sigaction_current[sig];
-	}
-	if (act) {
-		if (sig == SIGKILL) {
-			return errno = EINVAL, -1;
-		}
-		sigaction_current[sig] = (void*)act;
-	}
-	return 0;
-}
-
-int sigemptyset(sigset_t *set) {
-	(void)set;
-	return 0;
-}
-
-int sigfillset(sigset_t *set) {
-	(void)set;
-	return 0;
-}
-
-int sigprocmask(int how, const sigset_t *set, const sigset_t *oldset) {
-	return 0;
-}
-
-int sigsuspend(const sigset_t *mask) {
-	(void)mask;
-	__libc_panic("unimplemented");
-}
-
-int signal(int sig, void (*func)(int)) {
-	(void)sig; (void)func;
-	return errno = ENOSYS, SIG_ERR;
-}
-
-int kill(pid_t pid, int sig) {
-	(void)pid; (void)sig;
-	__libc_panic("unimplemented");
-}
-
-int raise(int sig) {
-	(void)sig;
-	__libc_panic("unimplemented");
-}
diff --git a/src/user/lib/stdio/file.c b/src/user/lib/stdio/file.c
deleted file mode 100644
index efaf013..0000000
--- a/src/user/lib/stdio/file.c
+++ /dev/null
@@ -1,359 +0,0 @@
-#include "file.h"
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <unistd.h>
-
-static FILE _stdin_null  = { .fd = STDIN_FILENO };
-static FILE _stdout_null = { .fd = STDOUT_FILENO };
-static FILE _stderr_null = { .fd = STDERR_FILENO };
-FILE *const stdin = &_stdin_null;
-FILE *const stdout = &_stdout_null;
-FILE *const stderr = &_stderr_null;
-
-
-FILE *fopen(const char *path, const char *mode) {
-	FILE *f;
-	hid_t h;
-	int flags = 0;
-	if (!path) {
-		errno = 1;
-		return NULL;
-	} else if (path[0] == '!') {
-		/* special handling for "!files" */
-		path++;
-		if (!strcmp(path, "stdin"))  return file_clone(stdin, mode);
-		if (!strcmp(path, "stdout")) return file_clone(stdout, mode);
-		if (!strcmp(path, "stderr")) return file_clone(stderr, mode);
-		errno = ENOENT;
-		return NULL;
-	}
-
-	if (strchr(mode, 'e')) {
-		/* camellia extension: open as executable */
-		flags |= OPEN_EXEC;
-	} else if (strchr(mode, 'r')) {
-		flags |= OPEN_READ;
-		if (strchr(mode, '+'))
-			flags |= OPEN_WRITE;
-	} else {
-		flags |= OPEN_WRITE | OPEN_CREATE;
-	}
-
-	h = camellia_open(path, flags);
-	if (h < 0) return NULL;
-
-	if (mode[0] == 'w')
-		_sys_write(h, NULL, 0, 0, WRITE_TRUNCATE);
-
-	f = fdopen(h, mode);
-	if (!f) close(h);
-	setvbuf(f, NULL, _IOFBF, 0);
-	return f;
-}
-
- FILE *freopen(const char *path, const char *mode, FILE *f) {
-	/* partially based on the musl implementation of freopen */
-	FILE *f2;
-	if (!path) goto fail;
-	f2 = fopen(path, mode);
-	if (!f2) goto fail;
-
-	if (f->fd == f2->fd) {
-		f2->fd = -1;
-	} else {
-		if (_sys_dup(f2->fd, f->fd, 0) < 0) goto fail2;
-	}
-	f->pos = f2->pos;
-	f->eof = f2->eof;
-	fclose(f2);
-	return f;
-
-fail2:
-	fclose(f2);
-fail:
-	fclose(f);
-	return NULL;
-}
-
-FILE *fdopen(int fd, const char *mode) {
-	FILE *f;
-	f = calloc(1, sizeof *f);
-	if (f) {
-		f->fd = fd;
-		f->pos = mode[0] == 'a' ? -1 : 0;
-	}
-	return f;
-}
-
-FILE *file_clone(const FILE *f, const char *mode) {
-	hid_t h = _sys_dup(f->fd, -1, 0);
-	FILE *f2;
-	if (h < 0) return NULL;
-
-	f2 = fdopen(h, mode);
-	if (!f2) {
-		close(h);
-		return NULL;
-	}
-	f2->pos = f->pos;
-	f2->eof = f->eof;
-	f2->fd = h;
-	return f2;
-}
-
-// TODO popen / pclose
-FILE *popen(const char *cmd, const char *mode) {
-	(void)cmd; (void)mode;
-	errno = ENOSYS;
-	return NULL;
-}
-
-int pclose(FILE *f) {
-	(void)f;
-	errno = ENOSYS;
-	return -1;
-}
-
-// TODO tmpfile()
-FILE *tmpfile(void) {
-	errno = ENOSYS;
-	return NULL;
-}
-
-
-int fextflags(FILE *f, int extflags) {
-	int old = f->extflags;
-	f->extflags = extflags;
-	return old;
-}
-
-int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size) {
-	if (type == _IONBF) {
-		free(f->readbuf);
-		f->readbuf = NULL;
-		return 0;
-	} else if (type == _IOFBF && buf == NULL) {
-		(void) size;
-		f->rblen = 0;
-		f->rbcap = BUFSIZ;
-		f->readbuf = malloc(f->rbcap);
-		return f->readbuf ? 0 : -1;
-	} else {
-		return errno = ENOSYS, -1;
-	}
-}
-
-static void fadvance(long amt, FILE *f) {
-	bool pos_neg = f->pos < 0;
-	f->pos += amt;
-	if (pos_neg && f->pos >= 0)
-		f->pos = -1;
-}
-
-size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict f) {
-	size_t total = size*nitems, pos = 0;
-	unsigned char *buf = ptr;
-
-	if (f->fd < 0) {
-		errno = EBADF;
-		return 0;
-	}
-	if (size == 0) {
-		return 0;
-	}
-
-	while (pos < total) {
-		long res = 0;
-		if (f->readbuf) {
-			if (0 == f->rblen && total - pos < (f->rbcap >> 1)) {
-				res = _sys_read(f->fd, f->readbuf, f->rbcap, f->pos);
-				if (res < 0) {
-					f->error = true;
-					errno = -res;
-					break;
-				} else if (res == 0) {
-					f->eof = true;
-					break;
-				} else {
-					f->rblen = res;
-				}
-			}
-			if (0 < f->rblen) {
-				res = MIN(total - pos, f->rblen);
-				memcpy(buf + pos, f->readbuf, res);
-				f->rblen -= res;
-				memmove(f->readbuf, f->readbuf + res, f->rblen);
-			}
-		}
-		if (res == 0) {
-			/* no cache hit */
-			res = _sys_read(f->fd, buf + pos, total - pos, f->pos);
-			if (res < 0) {
-				f->error = true;
-				errno = -res;
-				break;
-			} else if (res == 0) {
-				f->eof = true;
-				break;
-			}
-		}
-		pos += res;
-		fadvance(res, f);
-		if (f->extflags & FEXT_NOFILL) break;
-	}
-	return pos == total ? nitems : (pos/size);
-}
-
-size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict f) {
-	size_t total = size*nitems, pos = 0;
-	const unsigned char *buf = ptr;
-
-	if (f->fd < 0) {
-		errno = EBADF;
-		return 0;
-	}
-	if (size == 0)
-		return 0;
-
-	while (pos < total) {
-		long res = _sys_write(f->fd, buf + pos, total - pos, f->pos, 0);
-		if (res < 0) {
-			f->error = true;
-			errno = -res;
-			return pos/size;
-		} else if (res == 0) {
-			f->eof = true;
-			return pos/size;
-		} else {
-			pos += res;
-			fadvance(res, f);
-		}
-	}
-	return nitems;
-}
-
-int fputs(const char *s, FILE *f) {
-	return fprintf(f, "%s\n", s);
-}
-
-char *fgets(char *buf, int size, FILE *f) {
-	int pos, c;
-	for (pos = 0; pos < size-1; ) {
-		c = fgetc(f);
-		if (c == EOF) break;
-		buf[pos++] = c;
-		if (c == '\n') break;
-	}
-	if (pos == 0 || f->error) {
-		return NULL;
-	} else {
-		buf[pos] = '\0';
-		return buf;
-	}
-}
-
-int fgetc(FILE *f) {
-	char c;
-	size_t ret = fread(&c, 1, 1, f);
-	return ret ? c : EOF;
-}
-int getc(FILE *f) { return fgetc(f); }
-
-int fputc(int c, FILE *f) {
-	return fwrite(&c, 1, 1, f) ? c : EOF;
-}
-int putc(int c, FILE *f) { return fputc(c, f); }
-
-// TODO ungetc
-int ungetc(int c, FILE *f) {
-	(void)c; (void)f;
-	__libc_panic("unimplemented");
-}
-
-int fseek(FILE *f, long offset, int whence) {
-	return fseeko(f, offset, whence);
-}
-
-int fseeko(FILE *f, off_t offset, int whence) {
-	if (fflush(f))
-		return -1;
-
-	long base;
-	switch (whence) {
-		case SEEK_SET:
-			base = 0;
-			break;
-		case SEEK_CUR:
-			base = f->pos;
-			// TODO untested
-			if (f->readbuf) {
-				base -= f->rblen;
-			}
-			break;
-		case SEEK_END:
-			base = _sys_getsize(f->fd);
-			if (base < 0)
-				base = -1;
-			break;
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-	f->rblen = 0;
-
-	if (base >= 0 && base + offset < 0) {
-		/* underflow */
-		errno = EINVAL;
-		return -1;
-	} else if (base < 0 && base + offset >= 0) {
-		/* overflow - went from a negative offset (relative to EOF)
-		 *            to a positive offset (from start of file).
-		 *            can only happen when getsize() is unsupported */
-		errno = EINVAL;
-		return -1;
-	}
-	f->pos = base + offset;
-	f->eof = false;
-	return 0;
-}
-
-long ftell(FILE *f) {
-	return ftello(f);
-}
-
-off_t ftello(FILE *f) {
-	return f->pos;
-}
-
-int fclose(FILE *f) {
-	fflush(f);
-	if (f->fd > 0) close(f->fd);
-	free(f->readbuf);
-	if (f != &_stdin_null && f != &_stdout_null && f != &_stderr_null)
-		free(f);
-	return 0;
-}
-
-int fflush(FILE *f) {
-	(void)f;
-	return 0;
-}
-
-int feof(FILE *f) {
-	return f->eof;
-}
-
-int ferror(FILE *f) {
-	return f->error;
-}
-
-void clearerr(FILE *f) {
-	f->error = false;
-	f->eof = false;
-}
diff --git a/src/user/lib/stdio/file.h b/src/user/lib/stdio/file.h
deleted file mode 100644
index 3bd64a1..0000000
--- a/src/user/lib/stdio/file.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include <stdbool.h>
-#include <stdio.h>
-
-struct _LIBC_FILE {
-	int fd;
-	long pos;
-	bool eof;
-	bool error;
-	int extflags;
-
-	char *readbuf;
-	size_t rblen, rbcap;
-};
diff --git a/src/user/lib/stdio/misc.c b/src/user/lib/stdio/misc.c
deleted file mode 100644
index 45144f3..0000000
--- a/src/user/lib/stdio/misc.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-void perror(const char *s) {
-	if (s) fprintf(stderr, "%s: ", s);
-	fprintf(stderr, "%s\n", strerror(errno));
-}
-
-int puts(const char *s) {
-	return printf("%s\n", s);
-}
-
-int getchar(void) {
-	return fgetc(stdin);
-}
-
-int putchar(int c) {
-	return fputc(c, stdout);
-}
-
-off_t lseek(int fd, off_t off, int whence) {
-	(void)fd; (void)off; (void)whence;
-	errno = ENOSYS;
-	return -1;
-}
-
-int remove(const char *path) {
-	return unlink(path);
-}
-
-// TODO! VFSOP_MOVE
-int rename(const char *old, const char *new) {
-	(void)old; (void)new;
-	errno = ENOSYS;
-	return -1;
-}
-
-// TODO tmpnam
-char *tmpnam(char *s) {
-	static char buf[L_tmpnam];
-	if (!s) s = buf;
-	strcpy(s, "/tmp/tmpnam");
-	return s;
-}
-
-// TODO sscanf
-int sscanf(const char *restrict s, const char *restrict format, ...) {
-	(void)s; (void)format;
-	return 0;
-}
diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c
deleted file mode 100644
index 1739230..0000000
--- a/src/user/lib/stdlib.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include <_proc.h>
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <ctype.h>
-#include <errno.h>
-#include <string.h>
-
-_Noreturn void abort(void) {
-	_sys_exit(1);
-}
-
-static const char *progname;
-const char *getprogname(void) {
-	return progname;
-}
-void setprogname(const char *pg) {
-	progname = pg;
-	setproctitle(NULL);
-}
-
-void setproctitle(const char *fmt, ...) {
-	// TODO bounds checking
-	if (!fmt) {
-		strcpy(_psdata_loc->desc, progname);
-		return;
-	}
-	sprintf(_psdata_loc->desc, "%s: ", progname);
-
-	va_list argp;
-	va_start(argp, fmt);
-	vsnprintf(_psdata_loc->desc + strlen(_psdata_loc->desc), 128, fmt, argp);
-	va_end(argp);
-}
-
-int mkstemp(char *template) {
-	// TODO randomize template
-	hid_t h = camellia_open(template, OPEN_CREATE | OPEN_RW);
-	if (h < 0) {
-		errno = -h;
-		return -1;
-	}
-	// TODO truncate
-	return h;
-}
-
-// TODO process env
-char *getenv(const char *name) {
-	(void)name;
-	return NULL;
-}
-
-// TODO system()
-int system(const char *cmd) {
-	(void)cmd;
-	errno = ENOSYS;
-	return -1;
-}
-
-int abs(int i) {
-	return i < 0 ? -i : i;
-}
-
-int atoi(const char *s) {
-	return strtol(s, NULL, 10);
-}
-
-double atof(const char *s) {
-	(void)s;
-	__libc_panic("unimplemented");
-}
-
-static unsigned long long
-strton(const char *restrict s, char **restrict end, int base, int *sign)
-{
-	long res = 0;
-
-	while (isspace(*s)) s++;
-
-	if (sign) *sign = 1;
-	if (*s == '+') {
-		s++;
-	} else if (*s == '-') {
-		s++;
-		if (sign) *sign = -1;
-	}
-
-	if (base == 0) {
-		if (*s == '0') {
-			s++;
-			if (*s == 'x' || *s == 'X') {
-				s++;
-				base = 16;
-			} else {
-				base = 8;
-			}
-		} else {
-			base = 10;
-		}
-	}
-
-	for (;;) {
-		unsigned char digit = *s;
-		if      ('0' <= digit && digit <= '9') digit -= '0';
-		else if ('a' <= digit && digit <= 'z') digit -= 'a' - 10;
-		else if ('A' <= digit && digit <= 'Z') digit -= 'A' - 10;
-		else break;
-
-		if (digit >= base) break;
-		// TODO overflow check
-		res *= base;
-		res += digit;
-
-		s++;
-	}
-	if (end) *end = (void*)s;
-	return res;
-}
-
-long strtol(const char *restrict s, char **restrict end, int base) {
-	int sign;
-	long n = strton(s, end, base, &sign);
-	return n * sign;
-}
-
-long long strtoll(const char *restrict s, char **restrict end, int base) {
-	int sign;
-	long long n = strton(s, end, base, &sign);
-	return n * sign;
-}
-
-unsigned long strtoul(const char *restrict s, char **restrict end, int base) {
-	return strton(s, end, base, NULL);
-}
-
-unsigned long long strtoull(const char *restrict s, char **restrict end, int base) {
-	return strton(s, end, base, NULL);
-}
-
-double strtod(const char *restrict s, char **restrict end) {
-	(void)s; (void)end;
-	__libc_panic("unimplemented");
-}
-
-void qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *a, const void *b)) {
-	(void)base; (void)nmemb; (void)size; (void)cmp;
-	__libc_panic("unimplemented");
-}
diff --git a/src/user/lib/string/strerror.c b/src/user/lib/string/strerror.c
deleted file mode 100644
index c838299..0000000
--- a/src/user/lib/string/strerror.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <string.h>
-
-static const char *errstr[] = {
-#	define E(n, str) [n] = str,
-#	include <__errno.h>
-#	undef E
-};
-
-char *strerror(int n) {
-	if (0 <= n && n * sizeof(*errstr) < sizeof(errstr) && errstr[n])
-		return (char*)errstr[n];
-	return "unknown error";
-}
diff --git a/src/user/lib/string/string.c b/src/user/lib/string/string.c
deleted file mode 100644
index c65d7c5..0000000
--- a/src/user/lib/string/string.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-
-char *strchr(const char *s, int c) {
-	for (; *s || c == 0; s++) {
-		if (*s == c) return (char *)s;
-	}
-	return NULL;
-}
-
-char *strrchr(const char *s, int c) {
-	for (int i = strlen(s) + 1; i >= 0; i--) {
-		if (s[i] == c) return (char *)s + i;
-	}
-	return NULL;
-}
-
-size_t strspn(const char *s, const char *accept) {
-	size_t l = 0;
-	for (; s[l] && strchr(accept, s[l]); l++);
-	return l;
-}
-
-size_t strcspn(const char *s, const char *reject) {
-	size_t l = 0;
-	for (; s[l] && !strchr(reject, s[l]); l++);
-	return l;
-}
-
-char *strpbrk(const char *s1, const char *s2) {
-	for (; *s1; s1++) {
-		if (strchr(s2, *s1)) return (char*)s1;
-	}
-	return NULL;
-}
-
-char *strtok(char *restrict s, const char *restrict sep) {
-	static char *state;
-	return strtok_r(s, sep, &state);
-}
-
-char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state) {
-	char *end;
-	if (!s) s = *state;
-	s += strspn(s, sep); /* beginning of token */
-	if (!*s) return NULL;
-
-	end = s + strcspn(s, sep);
-	if (*end) {
-		*end = '\0';
-		*state = end + 1;
-	} else {
-		*state = end;
-	}
-	return s;
-}
-
-int strncmp(const char *s1, const char *s2, size_t n) {
-	for (size_t i = 0; i < n; i++) {
-		if (s1[i] < s2[i]) return -1;
-		if (s1[i] > s2[i]) return  1;
-	}
-	return 0;
-}
-
-int strcoll(const char *s1, const char *s2) {
-	return strcmp(s1, s2);
-}
-
-// TODO implement strstr using Boyer-Moore
-char *strstr(const char *s1, const char *s2) {
-	size_t l1 = strlen(s1), l2 = strlen(s2);
-	for (; l2 <= l1; s1++, l1--) {
-		if (memcmp(s1, s2, l2) == 0) return (char*)s1;
-	}
-	return NULL;
-}
-
-char *strcpy(char *restrict s1, const char *restrict s2) {
-	while (*s2) *s1++ = *s2++;
-	*s1 = *s2;
-	return s1;
-}
-
-char *strncpy(char *restrict dst, const char *restrict src, size_t n) {
-	for (size_t i = 0; i < n; i++) {
-		dst[i] = src[i];
-		if (dst[i] == '\0') return dst + i; // TODO fill with null bytes
-	}
-	return dst;
-}
-
-char *stpncpy(char *restrict dst, const char *restrict src, size_t n) {
-	return stpncpy(dst, src, n) + n;
-}
-
-char *strdup(const char *s) {
-	size_t len = strlen(s) + 1;
-	char *buf = malloc(len);
-	if (buf) memcpy(buf, s, len);
-	return buf;
-}
-
-/* strings.h */
-int strcasecmp(const char *s1, const char *s2) {
-	return strncasecmp(s1, s2, ~0);
-}
-
-int strncasecmp(const char *s1, const char *s2, size_t n) {
-	for (size_t i = 0; i < n; i++) {
-		char c1 = tolower(s1[i]), c2 = tolower(s2[i]);
-		if (c1 == '\0' || c1 != c2) {
-			if (c1 < c2)      return -1;
-			else if (c1 > c2) return 1;
-			else              return 0;
-		}
-	}
-	return 0;
-}
diff --git a/src/user/lib/syscall.c b/src/user/lib/syscall.c
deleted file mode 100644
index 5196683..0000000
--- a/src/user/lib/syscall.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* generated by syscall.c.awk
- * don't modify manually, instead run:
- *     make src/user/lib/syscall.c
- */
-#include <camellia/syscalls.h>
-
-
-_Noreturn void _sys_exit(long ret) {
-	_syscall(_SYS_EXIT, ret, 0, 0, 0, 0);
-	__builtin_unreachable();
-}
-
-long _sys_await(void) {
-	return _syscall(_SYS_AWAIT, 0, 0, 0, 0, 0);
-}
-
-long _sys_fork(int flags, hid_t __user *fs_front) {
-	return _syscall(_SYS_FORK, (long)flags, (long)fs_front, 0, 0, 0);
-}
-
-hid_t _sys_open(const char __user *path, long len, int flags) {
-	return (hid_t)_syscall(_SYS_OPEN, (long)path, len, (long)flags, 0, 0);
-}
-
-long _sys_mount(hid_t h, const char __user *path, long len) {
-	return _syscall(_SYS_MOUNT, (long)h, (long)path, len, 0, 0);
-}
-
-hid_t _sys_dup(hid_t from, hid_t to, int flags) {
-	return (hid_t)_syscall(_SYS_DUP, (long)from, (long)to, (long)flags, 0, 0);
-}
-
-long _sys_read(hid_t h, void __user *buf, size_t len, long offset) {
-	return _syscall(_SYS_READ, (long)h, (long)buf, (long)len, offset, 0);
-}
-
-long _sys_write(hid_t h, const void __user *buf, size_t len, long offset, int flags) {
-	return _syscall(_SYS_WRITE, (long)h, (long)buf, (long)len, offset, (long)flags);
-}
-
-long _sys_getsize(hid_t h) {
-	return _syscall(_SYS_GETSIZE, (long)h, 0, 0, 0, 0);
-}
-
-long _sys_remove(hid_t h) {
-	return _syscall(_SYS_REMOVE, (long)h, 0, 0, 0, 0);
-}
-
-long _sys_close(hid_t h) {
-	return _syscall(_SYS_CLOSE, (long)h, 0, 0, 0, 0);
-}
-
-hid_t _sys_fs_wait(char __user *buf, long max_len, struct ufs_request __user *res) {
-	return (hid_t)_syscall(_SYS_FS_WAIT, (long)buf, max_len, (long)res, 0, 0);
-}
-
-long _sys_fs_respond(hid_t hid, const void __user *buf, long ret, int flags) {
-	return _syscall(_SYS_FS_RESPOND, (long)hid, (long)buf, ret, (long)flags, 0);
-}
-
-void __user *_sys_memflag(void __user *addr, size_t len, int flags) {
-	return (void __user *)_syscall(_SYS_MEMFLAG, (long)addr, (long)len, (long)flags, 0, 0);
-}
-
-long _sys_pipe(hid_t __user user_ends[2], int flags) {
-	return _syscall(_SYS_PIPE, (long)user_ends, (long)flags, 0, 0, 0);
-}
-
-void _sys_sleep(long ms) {
-	return (void)_syscall(_SYS_SLEEP, ms, 0, 0, 0, 0);
-}
-
-void _sys_filicide(void) {
-	return (void)_syscall(_SYS_FILICIDE, 0, 0, 0, 0, 0);
-}
-
-void _sys_intr(void) {
-	return (void)_syscall(_SYS_INTR, 0, 0, 0, 0, 0);
-}
-
-void _sys_intr_set(void __user *ip) {
-	return (void)_syscall(_SYS_INTR_SET, (long)ip, 0, 0, 0, 0);
-}
-
-uint32_t _sys_getpid(void) {
-	return (uint32_t)_syscall(_SYS_GETPID, 0, 0, 0, 0, 0);
-}
-
-uint32_t _sys_getppid(void) {
-	return (uint32_t)_syscall(_SYS_GETPPID, 0, 0, 0, 0, 0);
-}
-
-int _sys_wait2(int pid, int flags, struct sys_wait2 __user *out) {
-	return (int)_syscall(_SYS_WAIT2, (long)pid, (long)flags, (long)out, 0, 0);
-}
-
-long _sys_execbuf(void __user *buf, size_t len) {
-	return _syscall(_SYS_EXECBUF, (long)buf, (long)len, 0, 0, 0);
-}
-
-void _sys_debug_klog(const void __user *buf, size_t len) {
-	return (void)_syscall(_SYS_DEBUG_KLOG, (long)buf, (long)len, 0, 0, 0);
-}
-
diff --git a/src/user/lib/syscall.c.awk b/src/user/lib/syscall.c.awk
deleted file mode 100644
index 591a6f0..0000000
--- a/src/user/lib/syscall.c.awk
+++ /dev/null
@@ -1,51 +0,0 @@
-BEGIN {
-	print "\
-/* generated by syscall.c.awk\n\
- * don't modify manually, instead run:\n\
- *     make src/user/lib/syscall.c\n\
- */\n\
-#include <camellia/syscalls.h>\n\
-\n";
-}
-
-/_syscall\(/ { next; } # skipping _syscall(), it's implemented elsewhere
-
-/\);/ {
-	sub(/;/, " {");
-	print $0;
-
-	name = substr($0, match($0, /_sys_[^(]+/), RLENGTH);
-	rets = substr($0, 0, RSTART - 1);
-	sub(/ *$/, "", rets)
-
-	params = substr($0, match($0, /\(.+\)/) + 1, RLENGTH - 2);
-	gsub(/\[[^\]]\]/, "", params);
-	if (params == "void") params = ""
-
-	split(params, p, /,/);
-	for (i = 0; i < 6; i += 1) {
-		if (p[i]) {
-			# p[i] is a parameter, convert it into an expression to pass to _syscall()
-			sub(/^ */, "", p[i]); # strip
-			split(p[i], words, / /);
-			if (length(words) != 1) {
-				var = words[length(words)];
-				sub(/\*/, "", var);
-				if (words[1] != "long") var = "(long)" var;
-			}
-			p[i] = var;
-		} else {
-			p[i] = 0;
-		}
-	}
-
-	printf "\t";
-	if (!index($0, "_Noreturn")) {
-		printf "return ";
-		if (rets != "long") printf "(%s)", rets;
-	}
-	printf "_syscall(%s, %s, %s, %s, %s, %s);\n", toupper(name), p[1], p[2], p[3], p[4], p[5];
-	if (index($0, "_Noreturn")) print "\t__builtin_unreachable();";
-
-	print "}\n";
-}
diff --git a/src/user/lib/syscall.s b/src/user/lib/syscall.s
deleted file mode 100644
index 07f5631..0000000
--- a/src/user/lib/syscall.s
+++ /dev/null
@@ -1,9 +0,0 @@
-.section .text
-.global _syscall
-.type _syscall, @function
-_syscall:
-	push %r10
-	mov %rcx, %r10
-	syscall
-	pop %r10
-	ret
diff --git a/src/user/lib/sysstat.c b/src/user/lib/sysstat.c
deleted file mode 100644
index 97bb50b..0000000
--- a/src/user/lib/sysstat.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <camellia.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-int fstat(int fd, struct stat *sb) {
-	(void)fd;
-	memset(sb, 0, sizeof sb);
-	// TODO save info if it was a dir
-	sb->st_mode = 0777 | S_IFREG;
-	return 0;
-}
-
-int stat(const char *restrict path, struct stat *restrict sb) {
-	int fd, ret;
-	fd = camellia_open(path, OPEN_READ);
-	if (fd < 0) {
-		return -1;
-	}
-	ret = fstat(fd, sb);
-	close(fd);
-	return ret;
-}
-
-int lstat(const char *restrict path, struct stat *restrict sb) {
-	// TODO assumes no symlink support
-	return stat(path, sb);
-}
-
-int mkdir(const char *path, mode_t mode) {
-	// TODO error when directory already exits
-	// TODO fopen-like wrapper that calls open() with a processed path
-	(void)mode;
-	size_t plen = strlen(path);
-	char *tmp = NULL;
-	/* ensure trailing slash */
-	if (plen >= 1 && path[plen - 1] != '/') {
-		tmp = malloc(plen + 2);
-		memcpy(tmp, path, plen);
-		tmp[plen] = '/';
-		tmp[plen + 1] = '\0';
-		path = tmp;
-	}
-	FILE *f = fopen(path, "a"); /* sets errno */
-	if (f) fclose(f);
-	free(tmp);
-	return f == NULL ? -1 : 0;
-}
diff --git a/src/user/lib/syswait.c b/src/user/lib/syswait.c
deleted file mode 100644
index ce80c7b..0000000
--- a/src/user/lib/syswait.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-
-pid_t wait3(int *wstatus, int opts, struct rusage *rusage) {
-	struct sys_wait2 res;
-	if (opts || rusage) {
-		__libc_panic("unimplemented");
-	}
-	pid_t ret = _sys_wait2(-1, 0, &res);
-	if (ret < 0) {
-		errno = -ret;
-		return -1;
-	}
-	if (wstatus) {
-		*wstatus = res.status & 0xFF;
-	}
-	return ret;
-}
diff --git a/src/user/lib/thread.S b/src/user/lib/thread.S
deleted file mode 100644
index 2900544..0000000
--- a/src/user/lib/thread.S
+++ /dev/null
@@ -1,40 +0,0 @@
-#define ASM_FILE 1
-#include <camellia/syscalls.h>
-#include <camellia/flags.h>
-
-.section .text
-.global thread_creates
-.type thread_creates, @function
-// void thread_creates(int flags, void (*fn)(void*), void *arg, void *stack);
-thread_creates:
-	push %r12
-	push %r13
-	push %r14
-
-	/* save fn, arg, stack */
-	mov %rsi, %r12
-	mov %rdx, %r13
-	mov %rcx, %r14
-
-	mov %rdi, %rsi
-	or $(FORK_SHAREMEM | FORK_SHAREHANDLE), %rsi
-	mov $_SYS_FORK, %rdi
-	xor %rdx, %rdx
-	syscall
-
-	test %rax, %rax
-	jz 1f
-	/* in parent, return normally */
-	pop %r14
-	pop %r13
-	pop %r12
-	ret
-1:	/* in child */
-	mov %r14, %rsp
-	mov %r13, %rdi
-	call *%r12
-
-	mov $_SYS_EXIT, %rdi
-	xor %rsi, %rsi
-	syscall
-	hlt /* if all else fails... */
diff --git a/src/user/lib/time.c b/src/user/lib/time.c
deleted file mode 100644
index 4709ecd..0000000
--- a/src/user/lib/time.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <errno.h>
-#include <time.h>
-
-// TODO time
-time_t time(time_t *tloc) {
-	time_t ret = 0;
-	if (tloc) *tloc = ret;
-	return ret;
-}
-
-clock_t clock(void) {
-	return 0;
-}
-
-struct tm *gmtime(const time_t *timer) {
-	(void)timer;
-	errno = ENOSYS;
-	return NULL;
-}
-
-struct tm *localtime(const time_t *timer) {
-	(void)timer;
-	errno = ENOSYS;
-	return NULL;
-}
-
-time_t mktime(struct tm *timeptr) {
-	(void)timeptr;
-	return 0;
-}
-
-double difftime(time_t time1, time_t time0) {
-	(void)time1; (void)time0;
-	return 0;
-}
-
-size_t strftime(
-	char *restrict s, size_t maxsize,
-	const char *restrict format, const struct tm *restrict timeptr)
-{
-	(void)s; (void)maxsize; (void)format; (void)timeptr;
-	return 0;
-}
diff --git a/src/user/lib/unistd.c b/src/user/lib/unistd.c
deleted file mode 100644
index 578cadc..0000000
--- a/src/user/lib/unistd.c
+++ /dev/null
@@ -1,267 +0,0 @@
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/path.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <elfload.h>
-
-int errno = 0;
-static char *_environ[] = {NULL};
-char **environ = _environ;
-
-int fork(void) {
-	return _sys_fork(0, NULL);
-}
-
-pid_t vfork(void) {
-	// TODO vfork is implemented improperly and will break stuff
-	return _sys_fork(0, NULL);
-}
-
-int close(hid_t h) {
-	return _sys_close(h);
-}
-
-_Noreturn void exit(int c) {
-	_sys_exit(c);
-}
-_Noreturn void _exit(int c) { exit(c); };
-
-ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize) {
-	(void)path; (void)buf; (void)bufsize;
-	errno = ENOSYS;
-	return -1;
-}
-
-int link(const char *path1, const char *path2) {
-	(void)path1; (void)path2;
-	errno = ENOSYS;
-	return -1;
-}
-
-int unlink(const char *path) {
-	hid_t h = camellia_open(path, OPEN_WRITE);
-	if (h < 0) return errno = -h, -1;
-	long ret = _sys_remove(h);
-	if (ret < 0) return errno = -ret, -1;
-	return 0;
-}
-
-int symlink(const char *path1, const char *path2) {
-	(void)path1; (void)path2;
-	errno = ENOSYS;
-	return -1;
-}
-
-// TODO isatty
-int isatty(int fd) {
-	return fd <= 2 ? 1 : 0;
-}
-
-
-int execv(const char *path, char *const argv[]) {
-	return execve(path, argv, NULL);
-}
-
-int execve(const char *path, char *const argv[], char *const envp[]) {
-	FILE *file = fopen(path, "e");
-	char hdr[4] = {0};
-	if (!file)
-		return -1;
-
-	fread(hdr, 1, 4, file);
-	fseek(file, 0, SEEK_SET);
-
-	if (!memcmp("\x7f""ELF", hdr, 4)) {
-		elf_execf(file, (void*)argv, (void*)envp);
-		fclose(file);
-	} else if (!memcmp("#!", hdr, 2)) {
-		char buf[256];
-		fseek(file, 2, SEEK_SET);
-		if (fgets(buf, sizeof buf, file)) {
-			const char *argv [] = {buf, path, NULL};
-			char *endl = strchr(buf, '\n');
-			if (endl) *endl = '\0';
-			execve(buf, (void*)argv, envp);
-		}
-	}
-
-	errno = EINVAL;
-	return -1;
-}
-
-
-static const char *__initialcwd;
-static char *cwd = NULL, *cwd2 = NULL;
-static size_t cwdcapacity = 0;
-
-static const char *getrealcwd(void) {
-	/* __initialcwd can't just be initialized with "/" because ld has seemingly
-	 * started to revolt against humanity and not process half the relocations
-	 * it sees. */
-	if (cwd) return cwd;
-	if (__initialcwd) return __initialcwd;
-	return "/";
-}
-
-int chdir(const char *path) {
-	hid_t h;
-	char *tmp;
-	size_t len = absolutepath(NULL, path, 0) + 1; /* +1 for the trailing slash */
-	if (cwdcapacity < len) {
-		cwdcapacity = len;
-		if (cwd) {
-			cwd = realloc(cwd, len);
-			cwd2 = realloc(cwd2, len);
-		} else {
-			size_t initlen = strlen(__initialcwd) + 1;
-			if (len < initlen)
-				len = initlen;
-			cwd = malloc(initlen);
-			cwd2 = malloc(initlen);
-			memcpy(cwd, __initialcwd, initlen);
-		}
-	}
-	absolutepath(cwd2, path, cwdcapacity);
-	len = strlen(cwd2);
-	if (cwd2[len - 1] != '/') {
-		cwd2[len] = '/';
-		cwd2[len + 1] = '\0';
-	}
-
-	/* check if exists */
-	h = camellia_open(cwd2, OPEN_READ);
-	if (h < 0) return errno = ENOENT, -1;
-	close(h);
-
-	tmp  = cwd;
-	cwd  = cwd2;
-	cwd2 = tmp;
-	return 0;
-}
-
-char *getcwd(char *buf, size_t capacity) {
-	const char *realcwd = getrealcwd();
-	size_t len = strlen(realcwd) + 1;
-	if (capacity < len) {
-		errno = capacity == 0 ? EINVAL : ERANGE;
-		return NULL;
-	}
-	memcpy(buf, realcwd, len);
-	return buf;
-}
-
-uid_t getuid(void) { return 0; }
-uid_t geteuid(void) { return 0; }
-gid_t getgid(void) { return 0; }
-gid_t getegid(void) { return 0; }
-
-int chown(const char *path, uid_t owner, gid_t group) {
-	(void)path; (void)owner; (void)group;
-	errno = ENOSYS;
-	return -1;
-}
-
-int setpgid(pid_t pid, pid_t pgid) {
-	(void)pid; (void)pgid;
-	return errno = ENOSYS, -1;
-}
-
-pid_t tcgetpgrp(int fd) {
-	(void)fd;
-	return errno = ENOSYS, -1;
-}
-
-int tcsetpgrp(int fd, pid_t pgrp) {
-	(void)fd; (void)pgrp;
-	return errno = ENOSYS, -1;
-}
-
-pid_t getpgrp(void) {
-	__libc_panic("unimplemented");
-}
-
-pid_t getpid(void) {
-	return _sys_getpid();
-}
-
-pid_t getppid(void) {
-	return _sys_getppid();
-}
-
-int getgroups(int size, gid_t list[]) {
-	(void)size; (void)list;
-	__libc_panic("unimplemented");
-}
-
-ssize_t read(int fd, void *buf, size_t count) {
-	// TODO real file descriptor emulation - store offsets
-	return _sys_read(fd, buf, count, -1);
-}
-
-ssize_t write(int fd, const void *buf, size_t count) {
-	// TODO real file descriptor emulation - store offsets
-	return _sys_write(fd, buf, count, -1, 0);
-}
-
-int pipe(int pipefd[2]) {
-	(void)pipefd;
-	__libc_panic("unimplemented");
-}
-
-int dup2(int oldfd, int newfd) {
-	(void)oldfd; (void)newfd;
-	__libc_panic("unimplemented");
-}
-
-size_t absolutepath(char *out, const char *in, size_t size) {
-	const char *realcwd = getrealcwd();
-	size_t len, pos = 0;
-	if (!in) return strlen(realcwd) + 1;
-
-	if (!(in[0] == '/')) {
-		len = strlen(realcwd);
-		if (pos + len <= size && out != realcwd)
-			memcpy(out + pos, realcwd, len);
-		pos += len;
-
-		if (realcwd[len - 1] != '/') {
-			if (pos + 1 <= size) out[pos] = '/';
-			pos++;
-		}
-	}
-
-	len = strlen(in);
-	if (pos + len <= size)
-		memcpy(out + pos, in, len);
-	pos += len;
-
-	if (pos <= size) {
-		pos = path_simplify(out, out, pos);
-		if (pos == 0) return 0;
-	}
-
-	if (pos + 1 <= size) out[pos] = '\0';
-	pos++;
-
-	return pos;
-}
-
-void __setinitialcwd(const char *s) {
-	__initialcwd = s;
-}
-
-static void intr_null(void) { }
-
-extern void (*volatile _intr)(void);
-void intr_set(void (*fn)(void)) {
-	_intr = fn ? fn : intr_null;
-}
-
-void intr_default(void) {
-	exit(-1);
-}
diff --git a/src/user/lib/vendor/dlmalloc/malloc.c b/src/user/lib/vendor/dlmalloc/malloc.c
deleted file mode 100644
index 649cfbc..0000000
--- a/src/user/lib/vendor/dlmalloc/malloc.c
+++ /dev/null
@@ -1,6280 +0,0 @@
-/*
-  This is a version (aka dlmalloc) of malloc/free/realloc written by
-  Doug Lea and released to the public domain, as explained at
-  http://creativecommons.org/publicdomain/zero/1.0/ Send questions,
-  comments, complaints, performance data, etc to dl@cs.oswego.edu
-
-* Version 2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea
-   Note: There may be an updated version of this malloc obtainable at
-           ftp://gee.cs.oswego.edu/pub/misc/malloc.c
-         Check before installing!
-
-* Quickstart
-
-  This library is all in one file to simplify the most common usage:
-  ftp it, compile it (-O3), and link it into another program. All of
-  the compile-time options default to reasonable values for use on
-  most platforms.  You might later want to step through various
-  compile-time and dynamic tuning options.
-
-  For convenience, an include file for code using this malloc is at:
-     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h
-  You don't really need this .h file unless you call functions not
-  defined in your system include files.  The .h file contains only the
-  excerpts from this file needed for using this malloc on ANSI C/C++
-  systems, so long as you haven't changed compile-time options about
-  naming and tuning parameters.  If you do, then you can create your
-  own malloc.h that does include all settings by cutting at the point
-  indicated below. Note that you may already by default be using a C
-  library containing a malloc that is based on some version of this
-  malloc (for example in linux). You might still want to use the one
-  in this file to customize settings or to avoid overheads associated
-  with library versions.
-
-* Vital statistics:
-
-  Supported pointer/size_t representation:       4 or 8 bytes
-       size_t MUST be an unsigned type of the same width as
-       pointers. (If you are using an ancient system that declares
-       size_t as a signed type, or need it to be a different width
-       than pointers, you can use a previous release of this malloc
-       (e.g. 2.7.2) supporting these.)
-
-  Alignment:                                     8 bytes (minimum)
-       This suffices for nearly all current machines and C compilers.
-       However, you can define MALLOC_ALIGNMENT to be wider than this
-       if necessary (up to 128bytes), at the expense of using more space.
-
-  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)
-                                          8 or 16 bytes (if 8byte sizes)
-       Each malloced chunk has a hidden word of overhead holding size
-       and status information, and additional cross-check word
-       if FOOTERS is defined.
-
-  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)
-                          8-byte ptrs:  32 bytes    (including overhead)
-
-       Even a request for zero bytes (i.e., malloc(0)) returns a
-       pointer to something of the minimum allocatable size.
-       The maximum overhead wastage (i.e., number of extra bytes
-       allocated than were requested in malloc) is less than or equal
-       to the minimum size, except for requests >= mmap_threshold that
-       are serviced via mmap(), where the worst case wastage is about
-       32 bytes plus the remainder from a system page (the minimal
-       mmap unit); typically 4096 or 8192 bytes.
-
-  Security: static-safe; optionally more or less
-       The "security" of malloc refers to the ability of malicious
-       code to accentuate the effects of errors (for example, freeing
-       space that is not currently malloc'ed or overwriting past the
-       ends of chunks) in code that calls malloc.  This malloc
-       guarantees not to modify any memory locations below the base of
-       heap, i.e., static variables, even in the presence of usage
-       errors.  The routines additionally detect most improper frees
-       and reallocs.  All this holds as long as the static bookkeeping
-       for malloc itself is not corrupted by some other means.  This
-       is only one aspect of security -- these checks do not, and
-       cannot, detect all possible programming errors.
-
-       If FOOTERS is defined nonzero, then each allocated chunk
-       carries an additional check word to verify that it was malloced
-       from its space.  These check words are the same within each
-       execution of a program using malloc, but differ across
-       executions, so externally crafted fake chunks cannot be
-       freed. This improves security by rejecting frees/reallocs that
-       could corrupt heap memory, in addition to the checks preventing
-       writes to statics that are always on.  This may further improve
-       security at the expense of time and space overhead.  (Note that
-       FOOTERS may also be worth using with MSPACES.)
-
-       By default detected errors cause the program to abort (calling
-       "abort()"). You can override this to instead proceed past
-       errors by defining PROCEED_ON_ERROR.  In this case, a bad free
-       has no effect, and a malloc that encounters a bad address
-       caused by user overwrites will ignore the bad address by
-       dropping pointers and indices to all known memory. This may
-       be appropriate for programs that should continue if at all
-       possible in the face of programming errors, although they may
-       run out of memory because dropped memory is never reclaimed.
-
-       If you don't like either of these options, you can define
-       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
-       else. And if if you are sure that your program using malloc has
-       no errors or vulnerabilities, you can define INSECURE to 1,
-       which might (or might not) provide a small performance improvement.
-
-       It is also possible to limit the maximum total allocatable
-       space, using malloc_set_footprint_limit. This is not
-       designed as a security feature in itself (calls to set limits
-       are not screened or privileged), but may be useful as one
-       aspect of a secure implementation.
-
-  Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero
-       When USE_LOCKS is defined, each public call to malloc, free,
-       etc is surrounded with a lock. By default, this uses a plain
-       pthread mutex, win32 critical section, or a spin-lock if if
-       available for the platform and not disabled by setting
-       USE_SPIN_LOCKS=0.  However, if USE_RECURSIVE_LOCKS is defined,
-       recursive versions are used instead (which are not required for
-       base functionality but may be needed in layered extensions).
-       Using a global lock is not especially fast, and can be a major
-       bottleneck.  It is designed only to provide minimal protection
-       in concurrent environments, and to provide a basis for
-       extensions.  If you are using malloc in a concurrent program,
-       consider instead using nedmalloc
-       (http://www.nedprod.com/programs/portable/nedmalloc/) or
-       ptmalloc (See http://www.malloc.de), which are derived from
-       versions of this malloc.
-
-  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
-       This malloc can use unix sbrk or any emulation (invoked using
-       the CALL_MORECORE macro) and/or mmap/munmap or any emulation
-       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
-       memory.  On most unix systems, it tends to work best if both
-       MORECORE and MMAP are enabled.  On Win32, it uses emulations
-       based on VirtualAlloc. It also uses common C library functions
-       like memset.
-
-  Compliance: I believe it is compliant with the Single Unix Specification
-       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
-       others as well.
-
-* Overview of algorithms
-
-  This is not the fastest, most space-conserving, most portable, or
-  most tunable malloc ever written. However it is among the fastest
-  while also being among the most space-conserving, portable and
-  tunable.  Consistent balance across these factors results in a good
-  general-purpose allocator for malloc-intensive programs.
-
-  In most ways, this malloc is a best-fit allocator. Generally, it
-  chooses the best-fitting existing chunk for a request, with ties
-  broken in approximately least-recently-used order. (This strategy
-  normally maintains low fragmentation.) However, for requests less
-  than 256bytes, it deviates from best-fit when there is not an
-  exactly fitting available chunk by preferring to use space adjacent
-  to that used for the previous small request, as well as by breaking
-  ties in approximately most-recently-used order. (These enhance
-  locality of series of small allocations.)  And for very large requests
-  (>= 256Kb by default), it relies on system memory mapping
-  facilities, if supported.  (This helps avoid carrying around and
-  possibly fragmenting memory used only for large chunks.)
-
-  All operations (except malloc_stats and mallinfo) have execution
-  times that are bounded by a constant factor of the number of bits in
-  a size_t, not counting any clearing in calloc or copying in realloc,
-  or actions surrounding MORECORE and MMAP that have times
-  proportional to the number of non-contiguous regions returned by
-  system allocation routines, which is often just 1. In real-time
-  applications, you can optionally suppress segment traversals using
-  NO_SEGMENT_TRAVERSAL, which assures bounded execution even when
-  system allocators return non-contiguous spaces, at the typical
-  expense of carrying around more memory and increased fragmentation.
-
-  The implementation is not very modular and seriously overuses
-  macros. Perhaps someday all C compilers will do as good a job
-  inlining modular code as can now be done by brute-force expansion,
-  but now, enough of them seem not to.
-
-  Some compilers issue a lot of warnings about code that is
-  dead/unreachable only on some platforms, and also about intentional
-  uses of negation on unsigned types. All known cases of each can be
-  ignored.
-
-  For a longer but out of date high-level description, see
-     http://gee.cs.oswego.edu/dl/html/malloc.html
-
-* MSPACES
-  If MSPACES is defined, then in addition to malloc, free, etc.,
-  this file also defines mspace_malloc, mspace_free, etc. These
-  are versions of malloc routines that take an "mspace" argument
-  obtained using create_mspace, to control all internal bookkeeping.
-  If ONLY_MSPACES is defined, only these versions are compiled.
-  So if you would like to use this allocator for only some allocations,
-  and your system malloc for others, you can compile with
-  ONLY_MSPACES and then do something like...
-    static mspace mymspace = create_mspace(0,0); // for example
-    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)
-
-  (Note: If you only need one instance of an mspace, you can instead
-  use "USE_DL_PREFIX" to relabel the global malloc.)
-
-  You can similarly create thread-local allocators by storing
-  mspaces as thread-locals. For example:
-    static __thread mspace tlms = 0;
-    void*  tlmalloc(size_t bytes) {
-      if (tlms == 0) tlms = create_mspace(0, 0);
-      return mspace_malloc(tlms, bytes);
-    }
-    void  tlfree(void* mem) { mspace_free(tlms, mem); }
-
-  Unless FOOTERS is defined, each mspace is completely independent.
-  You cannot allocate from one and free to another (although
-  conformance is only weakly checked, so usage errors are not always
-  caught). If FOOTERS is defined, then each chunk carries around a tag
-  indicating its originating mspace, and frees are directed to their
-  originating spaces. Normally, this requires use of locks.
-
- -------------------------  Compile-time options ---------------------------
-
-Be careful in setting #define values for numerical constants of type
-size_t. On some systems, literal values are not automatically extended
-to size_t precision unless they are explicitly casted. You can also
-use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.
-
-WIN32                    default: defined if _WIN32 defined
-  Defining WIN32 sets up defaults for MS environment and compilers.
-  Otherwise defaults are for unix. Beware that there seem to be some
-  cases where this malloc might not be a pure drop-in replacement for
-  Win32 malloc: Random-looking failures from Win32 GDI API's (eg;
-  SetDIBits()) may be due to bugs in some video driver implementations
-  when pixel buffers are malloc()ed, and the region spans more than
-  one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)
-  default granularity, pixel buffers may straddle virtual allocation
-  regions more often than when using the Microsoft allocator.  You can
-  avoid this by using VirtualAlloc() and VirtualFree() for all pixel
-  buffers rather than using malloc().  If this is not possible,
-  recompile this malloc with a larger DEFAULT_GRANULARITY. Note:
-  in cases where MSC and gcc (cygwin) are known to differ on WIN32,
-  conditions use _MSC_VER to distinguish them.
-
-DLMALLOC_EXPORT       default: extern
-  Defines how public APIs are declared. If you want to export via a
-  Windows DLL, you might define this as
-    #define DLMALLOC_EXPORT extern  __declspec(dllexport)
-  If you want a POSIX ELF shared object, you might use
-    #define DLMALLOC_EXPORT extern __attribute__((visibility("default")))
-
-MALLOC_ALIGNMENT         default: (size_t)(2 * sizeof(void *))
-  Controls the minimum alignment for malloc'ed chunks.  It must be a
-  power of two and at least 8, even on machines for which smaller
-  alignments would suffice. It may be defined as larger than this
-  though. Note however that code and data structures are optimized for
-  the case of 8-byte alignment.
-
-MSPACES                  default: 0 (false)
-  If true, compile in support for independent allocation spaces.
-  This is only supported if HAVE_MMAP is true.
-
-ONLY_MSPACES             default: 0 (false)
-  If true, only compile in mspace versions, not regular versions.
-
-USE_LOCKS                default: 0 (false)
-  Causes each call to each public routine to be surrounded with
-  pthread or WIN32 mutex lock/unlock. (If set true, this can be
-  overridden on a per-mspace basis for mspace versions.) If set to a
-  non-zero value other than 1, locks are used, but their
-  implementation is left out, so lock functions must be supplied manually,
-  as described below.
-
-USE_SPIN_LOCKS           default: 1 iff USE_LOCKS and spin locks available
-  If true, uses custom spin locks for locking. This is currently
-  supported only gcc >= 4.1, older gccs on x86 platforms, and recent
-  MS compilers.  Otherwise, posix locks or win32 critical sections are
-  used.
-
-USE_RECURSIVE_LOCKS      default: not defined
-  If defined nonzero, uses recursive (aka reentrant) locks, otherwise
-  uses plain mutexes. This is not required for malloc proper, but may
-  be needed for layered allocators such as nedmalloc.
-
-LOCK_AT_FORK            default: not defined
-  If defined nonzero, performs pthread_atfork upon initialization
-  to initialize child lock while holding parent lock. The implementation
-  assumes that pthread locks (not custom locks) are being used. In other
-  cases, you may need to customize the implementation.
-
-FOOTERS                  default: 0
-  If true, provide extra checking and dispatching by placing
-  information in the footers of allocated chunks. This adds
-  space and time overhead.
-
-INSECURE                 default: 0
-  If true, omit checks for usage errors and heap space overwrites.
-
-USE_DL_PREFIX            default: NOT defined
-  Causes compiler to prefix all public routines with the string 'dl'.
-  This can be useful when you only want to use this malloc in one part
-  of a program, using your regular system malloc elsewhere.
-
-MALLOC_INSPECT_ALL       default: NOT defined
-  If defined, compiles malloc_inspect_all and mspace_inspect_all, that
-  perform traversal of all heap space.  Unless access to these
-  functions is otherwise restricted, you probably do not want to
-  include them in secure implementations.
-
-ABORT                    default: defined as abort()
-  Defines how to abort on failed checks.  On most systems, a failed
-  check cannot die with an "assert" or even print an informative
-  message, because the underlying print routines in turn call malloc,
-  which will fail again.  Generally, the best policy is to simply call
-  abort(). It's not very useful to do more than this because many
-  errors due to overwriting will show up as address faults (null, odd
-  addresses etc) rather than malloc-triggered checks, so will also
-  abort.  Also, most compilers know that abort() does not return, so
-  can better optimize code conditionally calling it.
-
-PROCEED_ON_ERROR           default: defined as 0 (false)
-  Controls whether detected bad addresses cause them to bypassed
-  rather than aborting. If set, detected bad arguments to free and
-  realloc are ignored. And all bookkeeping information is zeroed out
-  upon a detected overwrite of freed heap space, thus losing the
-  ability to ever return it from malloc again, but enabling the
-  application to proceed. If PROCEED_ON_ERROR is defined, the
-  static variable malloc_corruption_error_count is compiled in
-  and can be examined to see if errors have occurred. This option
-  generates slower code than the default abort policy.
-
-DEBUG                    default: NOT defined
-  The DEBUG setting is mainly intended for people trying to modify
-  this code or diagnose problems when porting to new platforms.
-  However, it may also be able to better isolate user errors than just
-  using runtime checks.  The assertions in the check routines spell
-  out in more detail the assumptions and invariants underlying the
-  algorithms.  The checking is fairly extensive, and will slow down
-  execution noticeably. Calling malloc_stats or mallinfo with DEBUG
-  set will attempt to check every non-mmapped allocated and free chunk
-  in the course of computing the summaries.
-
-ABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)
-  Debugging assertion failures can be nearly impossible if your
-  version of the assert macro causes malloc to be called, which will
-  lead to a cascade of further failures, blowing the runtime stack.
-  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
-  which will usually make debugging easier.
-
-MALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32
-  The action to take before "return 0" when malloc fails to be able to
-  return memory because there is none available.
-
-HAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES
-  True if this system supports sbrk or an emulation of it.
-
-MORECORE                  default: sbrk
-  The name of the sbrk-style system routine to call to obtain more
-  memory.  See below for guidance on writing custom MORECORE
-  functions. The type of the argument to sbrk/MORECORE varies across
-  systems.  It cannot be size_t, because it supports negative
-  arguments, so it is normally the signed type of the same width as
-  size_t (sometimes declared as "intptr_t").  It doesn't much matter
-  though. Internally, we only call it with arguments less than half
-  the max value of a size_t, which should work across all reasonable
-  possibilities, although sometimes generating compiler warnings.
-
-MORECORE_CONTIGUOUS       default: 1 (true) if HAVE_MORECORE
-  If true, take advantage of fact that consecutive calls to MORECORE
-  with positive arguments always return contiguous increasing
-  addresses.  This is true of unix sbrk. It does not hurt too much to
-  set it true anyway, since malloc copes with non-contiguities.
-  Setting it false when definitely non-contiguous saves time
-  and possibly wasted space it would take to discover this though.
-
-MORECORE_CANNOT_TRIM      default: NOT defined
-  True if MORECORE cannot release space back to the system when given
-  negative arguments. This is generally necessary only if you are
-  using a hand-crafted MORECORE function that cannot handle negative
-  arguments.
-
-NO_SEGMENT_TRAVERSAL       default: 0
-  If non-zero, suppresses traversals of memory segments
-  returned by either MORECORE or CALL_MMAP. This disables
-  merging of segments that are contiguous, and selectively
-  releasing them to the OS if unused, but bounds execution times.
-
-HAVE_MMAP                 default: 1 (true)
-  True if this system supports mmap or an emulation of it.  If so, and
-  HAVE_MORECORE is not true, MMAP is used for all system
-  allocation. If set and HAVE_MORECORE is true as well, MMAP is
-  primarily used to directly allocate very large blocks. It is also
-  used as a backup strategy in cases where MORECORE fails to provide
-  space from system. Note: A single call to MUNMAP is assumed to be
-  able to unmap memory that may have be allocated using multiple calls
-  to MMAP, so long as they are adjacent.
-
-HAVE_MREMAP               default: 1 on linux, else 0
-  If true realloc() uses mremap() to re-allocate large blocks and
-  extend or shrink allocation spaces.
-
-MMAP_CLEARS               default: 1 except on WINCE.
-  True if mmap clears memory so calloc doesn't need to. This is true
-  for standard unix mmap using /dev/zero and on WIN32 except for WINCE.
-
-USE_BUILTIN_FFS            default: 0 (i.e., not used)
-  Causes malloc to use the builtin ffs() function to compute indices.
-  Some compilers may recognize and intrinsify ffs to be faster than the
-  supplied C version. Also, the case of x86 using gcc is special-cased
-  to an asm instruction, so is already as fast as it can be, and so
-  this setting has no effect. Similarly for Win32 under recent MS compilers.
-  (On most x86s, the asm version is only slightly faster than the C version.)
-
-malloc_getpagesize         default: derive from system includes, or 4096.
-  The system page size. To the extent possible, this malloc manages
-  memory from the system in page-size units.  This may be (and
-  usually is) a function rather than a constant. This is ignored
-  if WIN32, where page size is determined using getSystemInfo during
-  initialization.
-
-USE_DEV_RANDOM             default: 0 (i.e., not used)
-  Causes malloc to use /dev/random to initialize secure magic seed for
-  stamping footers. Otherwise, the current time is used.
-
-NO_MALLINFO                default: 0
-  If defined, don't compile "mallinfo". This can be a simple way
-  of dealing with mismatches between system declarations and
-  those in this file.
-
-MALLINFO_FIELD_TYPE        default: size_t
-  The type of the fields in the mallinfo struct. This was originally
-  defined as "int" in SVID etc, but is more usefully defined as
-  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set
-
-NO_MALLOC_STATS            default: 0
-  If defined, don't compile "malloc_stats". This avoids calls to
-  fprintf and bringing in stdio dependencies you might not want.
-
-REALLOC_ZERO_BYTES_FREES    default: not defined
-  This should be set if a call to realloc with zero bytes should
-  be the same as a call to free. Some people think it should. Otherwise,
-  since this malloc returns a unique pointer for malloc(0), so does
-  realloc(p, 0).
-
-LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
-LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H
-LACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H  default: NOT defined unless on WIN32
-  Define these if your system does not have these header files.
-  You might need to manually insert some of the declarations they provide.
-
-DEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,
-                                system_info.dwAllocationGranularity in WIN32,
-                                otherwise 64K.
-      Also settable using mallopt(M_GRANULARITY, x)
-  The unit for allocating and deallocating memory from the system.  On
-  most systems with contiguous MORECORE, there is no reason to
-  make this more than a page. However, systems with MMAP tend to
-  either require or encourage larger granularities.  You can increase
-  this value to prevent system allocation functions to be called so
-  often, especially if they are slow.  The value must be at least one
-  page and must be a power of two.  Setting to 0 causes initialization
-  to either page size or win32 region size.  (Note: In previous
-  versions of malloc, the equivalent of this option was called
-  "TOP_PAD")
-
-DEFAULT_TRIM_THRESHOLD    default: 2MB
-      Also settable using mallopt(M_TRIM_THRESHOLD, x)
-  The maximum amount of unused top-most memory to keep before
-  releasing via malloc_trim in free().  Automatic trimming is mainly
-  useful in long-lived programs using contiguous MORECORE.  Because
-  trimming via sbrk can be slow on some systems, and can sometimes be
-  wasteful (in cases where programs immediately afterward allocate
-  more large chunks) the value should be high enough so that your
-  overall system performance would improve by releasing this much
-  memory.  As a rough guide, you might set to a value close to the
-  average size of a process (program) running on your system.
-  Releasing this much memory would allow such a process to run in
-  memory.  Generally, it is worth tuning trim thresholds when a
-  program undergoes phases where several large chunks are allocated
-  and released in ways that can reuse each other's storage, perhaps
-  mixed with phases where there are no such chunks at all. The trim
-  value must be greater than page size to have any useful effect.  To
-  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
-  some people use of mallocing a huge space and then freeing it at
-  program startup, in an attempt to reserve system memory, doesn't
-  have the intended effect under automatic trimming, since that memory
-  will immediately be returned to the system.
-
-DEFAULT_MMAP_THRESHOLD       default: 256K
-      Also settable using mallopt(M_MMAP_THRESHOLD, x)
-  The request size threshold for using MMAP to directly service a
-  request. Requests of at least this size that cannot be allocated
-  using already-existing space will be serviced via mmap.  (If enough
-  normal freed space already exists it is used instead.)  Using mmap
-  segregates relatively large chunks of memory so that they can be
-  individually obtained and released from the host system. A request
-  serviced through mmap is never reused by any other request (at least
-  not directly; the system may just so happen to remap successive
-  requests to the same locations).  Segregating space in this way has
-  the benefits that: Mmapped space can always be individually released
-  back to the system, which helps keep the system level memory demands
-  of a long-lived program low.  Also, mapped memory doesn't become
-  `locked' between other chunks, as can happen with normally allocated
-  chunks, which means that even trimming via malloc_trim would not
-  release them.  However, it has the disadvantage that the space
-  cannot be reclaimed, consolidated, and then used to service later
-  requests, as happens with normal chunks.  The advantages of mmap
-  nearly always outweigh disadvantages for "large" chunks, but the
-  value of "large" may vary across systems.  The default is an
-  empirically derived value that works well in most systems. You can
-  disable mmap by setting to MAX_SIZE_T.
-
-MAX_RELEASE_CHECK_RATE   default: 4095 unless not HAVE_MMAP
-  The number of consolidated frees between checks to release
-  unused segments when freeing. When using non-contiguous segments,
-  especially with multiple mspaces, checking only for topmost space
-  doesn't always suffice to trigger trimming. To compensate for this,
-  free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
-  current number of segments, if greater) try to release unused
-  segments to the OS when freeing chunks that result in
-  consolidation. The best value for this parameter is a compromise
-  between slowing down frees with relatively costly checks that
-  rarely trigger versus holding on to unused memory. To effectively
-  disable, set to MAX_SIZE_T. This may lead to a very slight speed
-  improvement at the expense of carrying around more memory.
-*/
-
-/* Version identifier to allow people to support multiple versions */
-#ifndef DLMALLOC_VERSION
-#define DLMALLOC_VERSION 20806
-#endif /* DLMALLOC_VERSION */
-
-#ifndef DLMALLOC_EXPORT
-#define DLMALLOC_EXPORT extern
-#endif
-
-#ifndef WIN32
-#ifdef _WIN32
-#define WIN32 1
-#endif  /* _WIN32 */
-#ifdef _WIN32_WCE
-#define LACKS_FCNTL_H
-#define WIN32 1
-#endif /* _WIN32_WCE */
-#endif  /* WIN32 */
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <tchar.h>
-#define HAVE_MMAP 1
-#define HAVE_MORECORE 0
-#define LACKS_UNISTD_H
-#define LACKS_SYS_PARAM_H
-#define LACKS_SYS_MMAN_H
-#define LACKS_STRING_H
-#define LACKS_STRINGS_H
-#define LACKS_SYS_TYPES_H
-#define LACKS_ERRNO_H
-#define LACKS_SCHED_H
-#ifndef MALLOC_FAILURE_ACTION
-#define MALLOC_FAILURE_ACTION
-#endif /* MALLOC_FAILURE_ACTION */
-#ifndef MMAP_CLEARS
-#ifdef _WIN32_WCE /* WINCE reportedly does not clear */
-#define MMAP_CLEARS 0
-#else
-#define MMAP_CLEARS 1
-#endif /* _WIN32_WCE */
-#endif /*MMAP_CLEARS */
-#endif  /* WIN32 */
-
-#if defined(DARWIN) || defined(_DARWIN)
-/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
-#ifndef HAVE_MORECORE
-#define HAVE_MORECORE 0
-#define HAVE_MMAP 1
-/* OSX allocators provide 16 byte alignment */
-#ifndef MALLOC_ALIGNMENT
-#define MALLOC_ALIGNMENT ((size_t)16U)
-#endif
-#endif  /* HAVE_MORECORE */
-#endif  /* DARWIN */
-
-#ifndef LACKS_SYS_TYPES_H
-#include <sys/types.h>  /* For size_t */
-#endif  /* LACKS_SYS_TYPES_H */
-
-/* The maximum possible size_t value has all bits set */
-#define MAX_SIZE_T           (~(size_t)0)
-
-#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */
-#define USE_LOCKS  ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \
-                    (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0))
-#endif /* USE_LOCKS */
-
-#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */
-#if ((defined(__GNUC__) &&                                              \
-      ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) ||      \
-       defined(__i386__) || defined(__x86_64__))) ||                    \
-     (defined(_MSC_VER) && _MSC_VER>=1310))
-#ifndef USE_SPIN_LOCKS
-#define USE_SPIN_LOCKS 1
-#endif /* USE_SPIN_LOCKS */
-#elif USE_SPIN_LOCKS
-#error "USE_SPIN_LOCKS defined without implementation"
-#endif /* ... locks available... */
-#elif !defined(USE_SPIN_LOCKS)
-#define USE_SPIN_LOCKS 0
-#endif /* USE_LOCKS */
-
-#ifndef ONLY_MSPACES
-#define ONLY_MSPACES 0
-#endif  /* ONLY_MSPACES */
-#ifndef MSPACES
-#if ONLY_MSPACES
-#define MSPACES 1
-#else   /* ONLY_MSPACES */
-#define MSPACES 0
-#endif  /* ONLY_MSPACES */
-#endif  /* MSPACES */
-#ifndef MALLOC_ALIGNMENT
-#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))
-#endif  /* MALLOC_ALIGNMENT */
-#ifndef FOOTERS
-#define FOOTERS 0
-#endif  /* FOOTERS */
-#ifndef ABORT
-#define ABORT  abort()
-#endif  /* ABORT */
-#ifndef ABORT_ON_ASSERT_FAILURE
-#define ABORT_ON_ASSERT_FAILURE 1
-#endif  /* ABORT_ON_ASSERT_FAILURE */
-#ifndef PROCEED_ON_ERROR
-#define PROCEED_ON_ERROR 0
-#endif  /* PROCEED_ON_ERROR */
-
-#ifndef INSECURE
-#define INSECURE 0
-#endif  /* INSECURE */
-#ifndef MALLOC_INSPECT_ALL
-#define MALLOC_INSPECT_ALL 0
-#endif  /* MALLOC_INSPECT_ALL */
-#ifndef HAVE_MMAP
-#define HAVE_MMAP 1
-#endif  /* HAVE_MMAP */
-#ifndef MMAP_CLEARS
-#define MMAP_CLEARS 1
-#endif  /* MMAP_CLEARS */
-#ifndef HAVE_MREMAP
-#ifdef linux
-#define HAVE_MREMAP 1
-#define _GNU_SOURCE /* Turns on mremap() definition */
-#else   /* linux */
-#define HAVE_MREMAP 0
-#endif  /* linux */
-#endif  /* HAVE_MREMAP */
-#ifndef MALLOC_FAILURE_ACTION
-#define MALLOC_FAILURE_ACTION  errno = ENOMEM;
-#endif  /* MALLOC_FAILURE_ACTION */
-#ifndef HAVE_MORECORE
-#if ONLY_MSPACES
-#define HAVE_MORECORE 0
-#else   /* ONLY_MSPACES */
-#define HAVE_MORECORE 1
-#endif  /* ONLY_MSPACES */
-#endif  /* HAVE_MORECORE */
-#if !HAVE_MORECORE
-#define MORECORE_CONTIGUOUS 0
-#else   /* !HAVE_MORECORE */
-#define MORECORE_DEFAULT sbrk
-#ifndef MORECORE_CONTIGUOUS
-#define MORECORE_CONTIGUOUS 1
-#endif  /* MORECORE_CONTIGUOUS */
-#endif  /* HAVE_MORECORE */
-#ifndef DEFAULT_GRANULARITY
-#if (MORECORE_CONTIGUOUS || defined(WIN32))
-#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */
-#else   /* MORECORE_CONTIGUOUS */
-#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
-#endif  /* MORECORE_CONTIGUOUS */
-#endif  /* DEFAULT_GRANULARITY */
-#ifndef DEFAULT_TRIM_THRESHOLD
-#ifndef MORECORE_CANNOT_TRIM
-#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
-#else   /* MORECORE_CANNOT_TRIM */
-#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
-#endif  /* MORECORE_CANNOT_TRIM */
-#endif  /* DEFAULT_TRIM_THRESHOLD */
-#ifndef DEFAULT_MMAP_THRESHOLD
-#if HAVE_MMAP
-#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
-#else   /* HAVE_MMAP */
-#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
-#endif  /* HAVE_MMAP */
-#endif  /* DEFAULT_MMAP_THRESHOLD */
-#ifndef MAX_RELEASE_CHECK_RATE
-#if HAVE_MMAP
-#define MAX_RELEASE_CHECK_RATE 4095
-#else
-#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T
-#endif /* HAVE_MMAP */
-#endif /* MAX_RELEASE_CHECK_RATE */
-#ifndef USE_BUILTIN_FFS
-#define USE_BUILTIN_FFS 0
-#endif  /* USE_BUILTIN_FFS */
-#ifndef USE_DEV_RANDOM
-#define USE_DEV_RANDOM 0
-#endif  /* USE_DEV_RANDOM */
-#ifndef NO_MALLINFO
-#define NO_MALLINFO 0
-#endif  /* NO_MALLINFO */
-#ifndef MALLINFO_FIELD_TYPE
-#define MALLINFO_FIELD_TYPE size_t
-#endif  /* MALLINFO_FIELD_TYPE */
-#ifndef NO_MALLOC_STATS
-#define NO_MALLOC_STATS 0
-#endif  /* NO_MALLOC_STATS */
-#ifndef NO_SEGMENT_TRAVERSAL
-#define NO_SEGMENT_TRAVERSAL 0
-#endif /* NO_SEGMENT_TRAVERSAL */
-
-/*
-  mallopt tuning options.  SVID/XPG defines four standard parameter
-  numbers for mallopt, normally defined in malloc.h.  None of these
-  are used in this malloc, so setting them has no effect. But this
-  malloc does support the following options.
-*/
-
-#define M_TRIM_THRESHOLD     (-1)
-#define M_GRANULARITY        (-2)
-#define M_MMAP_THRESHOLD     (-3)
-
-/* ------------------------ Mallinfo declarations ------------------------ */
-
-#if !NO_MALLINFO
-/*
-  This version of malloc supports the standard SVID/XPG mallinfo
-  routine that returns a struct containing usage properties and
-  statistics. It should work on any system that has a
-  /usr/include/malloc.h defining struct mallinfo.  The main
-  declaration needed is the mallinfo struct that is returned (by-copy)
-  by mallinfo().  The malloinfo struct contains a bunch of fields that
-  are not even meaningful in this version of malloc.  These fields are
-  are instead filled by mallinfo() with other numbers that might be of
-  interest.
-
-  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
-  /usr/include/malloc.h file that includes a declaration of struct
-  mallinfo.  If so, it is included; else a compliant version is
-  declared below.  These must be precisely the same for mallinfo() to
-  work.  The original SVID version of this struct, defined on most
-  systems with mallinfo, declares all fields as ints. But some others
-  define as unsigned long. If your system defines the fields using a
-  type of different width than listed here, you MUST #include your
-  system version and #define HAVE_USR_INCLUDE_MALLOC_H.
-*/
-
-/* #define HAVE_USR_INCLUDE_MALLOC_H */
-
-#ifdef HAVE_USR_INCLUDE_MALLOC_H
-#include "/usr/include/malloc.h"
-#else /* HAVE_USR_INCLUDE_MALLOC_H */
-#ifndef STRUCT_MALLINFO_DECLARED
-/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */
-#define _STRUCT_MALLINFO
-#define STRUCT_MALLINFO_DECLARED 1
-struct mallinfo {
-  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
-  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
-  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
-  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
-  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
-  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
-  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
-  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
-  MALLINFO_FIELD_TYPE fordblks; /* total free space */
-  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
-};
-#endif /* STRUCT_MALLINFO_DECLARED */
-#endif /* HAVE_USR_INCLUDE_MALLOC_H */
-#endif /* NO_MALLINFO */
-
-/*
-  Try to persuade compilers to inline. The most critical functions for
-  inlining are defined as macros, so these aren't used for them.
-*/
-
-#ifndef FORCEINLINE
-  #if defined(__GNUC__)
-#define FORCEINLINE __inline __attribute__ ((always_inline))
-  #elif defined(_MSC_VER)
-    #define FORCEINLINE __forceinline
-  #endif
-#endif
-#ifndef NOINLINE
-  #if defined(__GNUC__)
-    #define NOINLINE __attribute__ ((noinline))
-  #elif defined(_MSC_VER)
-    #define NOINLINE __declspec(noinline)
-  #else
-    #define NOINLINE
-  #endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#ifndef FORCEINLINE
- #define FORCEINLINE inline
-#endif
-#endif /* __cplusplus */
-#ifndef FORCEINLINE
- #define FORCEINLINE
-#endif
-
-#if !ONLY_MSPACES
-
-/* ------------------- Declarations of public routines ------------------- */
-
-#ifndef USE_DL_PREFIX
-#define dlcalloc               calloc
-#define dlfree                 free
-#define dlmalloc               malloc
-#define dlmemalign             memalign
-#define dlposix_memalign       posix_memalign
-#define dlrealloc              realloc
-#define dlrealloc_in_place     realloc_in_place
-#define dlvalloc               valloc
-#define dlpvalloc              pvalloc
-#define dlmallinfo             mallinfo
-#define dlmallopt              mallopt
-#define dlmalloc_trim          malloc_trim
-#define dlmalloc_stats         malloc_stats
-#define dlmalloc_usable_size   malloc_usable_size
-#define dlmalloc_footprint     malloc_footprint
-#define dlmalloc_max_footprint malloc_max_footprint
-#define dlmalloc_footprint_limit malloc_footprint_limit
-#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
-#define dlmalloc_inspect_all   malloc_inspect_all
-#define dlindependent_calloc   independent_calloc
-#define dlindependent_comalloc independent_comalloc
-#define dlbulk_free            bulk_free
-#endif /* USE_DL_PREFIX */
-
-/*
-  malloc(size_t n)
-  Returns a pointer to a newly allocated chunk of at least n bytes, or
-  null if no space is available, in which case errno is set to ENOMEM
-  on ANSI C systems.
-
-  If n is zero, malloc returns a minimum-sized chunk. (The minimum
-  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
-  systems.)  Note that size_t is an unsigned type, so calls with
-  arguments that would be negative if signed are interpreted as
-  requests for huge amounts of space, which will often fail. The
-  maximum supported value of n differs across systems, but is in all
-  cases less than the maximum representable value of a size_t.
-*/
-DLMALLOC_EXPORT void* dlmalloc(size_t);
-
-/*
-  free(void* p)
-  Releases the chunk of memory pointed to by p, that had been previously
-  allocated using malloc or a related routine such as realloc.
-  It has no effect if p is null. If p was not malloced or already
-  freed, free(p) will by default cause the current program to abort.
-*/
-DLMALLOC_EXPORT void  dlfree(void*);
-
-/*
-  calloc(size_t n_elements, size_t element_size);
-  Returns a pointer to n_elements * element_size bytes, with all locations
-  set to zero.
-*/
-DLMALLOC_EXPORT void* dlcalloc(size_t, size_t);
-
-/*
-  realloc(void* p, size_t n)
-  Returns a pointer to a chunk of size n that contains the same data
-  as does chunk p up to the minimum of (n, p's size) bytes, or null
-  if no space is available.
-
-  The returned pointer may or may not be the same as p. The algorithm
-  prefers extending p in most cases when possible, otherwise it
-  employs the equivalent of a malloc-copy-free sequence.
-
-  If p is null, realloc is equivalent to malloc.
-
-  If space is not available, realloc returns null, errno is set (if on
-  ANSI) and p is NOT freed.
-
-  if n is for fewer bytes than already held by p, the newly unused
-  space is lopped off and freed if possible.  realloc with a size
-  argument of zero (re)allocates a minimum-sized chunk.
-
-  The old unix realloc convention of allowing the last-free'd chunk
-  to be used as an argument to realloc is not supported.
-*/
-DLMALLOC_EXPORT void* dlrealloc(void*, size_t);
-
-/*
-  realloc_in_place(void* p, size_t n)
-  Resizes the space allocated for p to size n, only if this can be
-  done without moving p (i.e., only if there is adjacent space
-  available if n is greater than p's current allocated size, or n is
-  less than or equal to p's size). This may be used instead of plain
-  realloc if an alternative allocation strategy is needed upon failure
-  to expand space; for example, reallocation of a buffer that must be
-  memory-aligned or cleared. You can use realloc_in_place to trigger
-  these alternatives only when needed.
-
-  Returns p if successful; otherwise null.
-*/
-DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t);
-
-/*
-  memalign(size_t alignment, size_t n);
-  Returns a pointer to a newly allocated chunk of n bytes, aligned
-  in accord with the alignment argument.
-
-  The alignment argument should be a power of two. If the argument is
-  not a power of two, the nearest greater power is used.
-  8-byte alignment is guaranteed by normal malloc calls, so don't
-  bother calling memalign with an argument of 8 or less.
-
-  Overreliance on memalign is a sure way to fragment space.
-*/
-DLMALLOC_EXPORT void* dlmemalign(size_t, size_t);
-
-/*
-  int posix_memalign(void** pp, size_t alignment, size_t n);
-  Allocates a chunk of n bytes, aligned in accord with the alignment
-  argument. Differs from memalign only in that it (1) assigns the
-  allocated memory to *pp rather than returning it, (2) fails and
-  returns EINVAL if the alignment is not a power of two (3) fails and
-  returns ENOMEM if memory cannot be allocated.
-*/
-DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t);
-
-/*
-  valloc(size_t n);
-  Equivalent to memalign(pagesize, n), where pagesize is the page
-  size of the system. If the pagesize is unknown, 4096 is used.
-*/
-DLMALLOC_EXPORT void* dlvalloc(size_t);
-
-/*
-  mallopt(int parameter_number, int parameter_value)
-  Sets tunable parameters The format is to provide a
-  (parameter-number, parameter-value) pair.  mallopt then sets the
-  corresponding parameter to the argument value if it can (i.e., so
-  long as the value is meaningful), and returns 1 if successful else
-  0.  To workaround the fact that mallopt is specified to use int,
-  not size_t parameters, the value -1 is specially treated as the
-  maximum unsigned size_t value.
-
-  SVID/XPG/ANSI defines four standard param numbers for mallopt,
-  normally defined in malloc.h.  None of these are use in this malloc,
-  so setting them has no effect. But this malloc also supports other
-  options in mallopt. See below for details.  Briefly, supported
-  parameters are as follows (listed defaults are for "typical"
-  configurations).
-
-  Symbol            param #  default    allowed param values
-  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1 disables)
-  M_GRANULARITY        -2     page size   any power of 2 >= page size
-  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
-*/
-DLMALLOC_EXPORT int dlmallopt(int, int);
-
-/*
-  malloc_footprint();
-  Returns the number of bytes obtained from the system.  The total
-  number of bytes allocated by malloc, realloc etc., is less than this
-  value. Unlike mallinfo, this function returns only a precomputed
-  result, so can be called frequently to monitor memory consumption.
-  Even if locks are otherwise defined, this function does not use them,
-  so results might not be up to date.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_footprint(void);
-
-/*
-  malloc_max_footprint();
-  Returns the maximum number of bytes obtained from the system. This
-  value will be greater than current footprint if deallocated space
-  has been reclaimed by the system. The peak number of bytes allocated
-  by malloc, realloc etc., is less than this value. Unlike mallinfo,
-  this function returns only a precomputed result, so can be called
-  frequently to monitor memory consumption.  Even if locks are
-  otherwise defined, this function does not use them, so results might
-  not be up to date.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void);
-
-/*
-  malloc_footprint_limit();
-  Returns the number of bytes that the heap is allowed to obtain from
-  the system, returning the last value returned by
-  malloc_set_footprint_limit, or the maximum size_t value if
-  never set. The returned value reflects a permission. There is no
-  guarantee that this number of bytes can actually be obtained from
-  the system.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_footprint_limit();
-
-/*
-  malloc_set_footprint_limit();
-  Sets the maximum number of bytes to obtain from the system, causing
-  failure returns from malloc and related functions upon attempts to
-  exceed this value. The argument value may be subject to page
-  rounding to an enforceable limit; this actual value is returned.
-  Using an argument of the maximum possible size_t effectively
-  disables checks. If the argument is less than or equal to the
-  current malloc_footprint, then all future allocations that require
-  additional system memory will fail. However, invocation cannot
-  retroactively deallocate existing used memory.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes);
-
-#if MALLOC_INSPECT_ALL
-/*
-  malloc_inspect_all(void(*handler)(void *start,
-                                    void *end,
-                                    size_t used_bytes,
-                                    void* callback_arg),
-                      void* arg);
-  Traverses the heap and calls the given handler for each managed
-  region, skipping all bytes that are (or may be) used for bookkeeping
-  purposes.  Traversal does not include include chunks that have been
-  directly memory mapped. Each reported region begins at the start
-  address, and continues up to but not including the end address.  The
-  first used_bytes of the region contain allocated data. If
-  used_bytes is zero, the region is unallocated. The handler is
-  invoked with the given callback argument. If locks are defined, they
-  are held during the entire traversal. It is a bad idea to invoke
-  other malloc functions from within the handler.
-
-  For example, to count the number of in-use chunks with size greater
-  than 1000, you could write:
-  static int count = 0;
-  void count_chunks(void* start, void* end, size_t used, void* arg) {
-    if (used >= 1000) ++count;
-  }
-  then:
-    malloc_inspect_all(count_chunks, NULL);
-
-  malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
-*/
-DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
-                           void* arg);
-
-#endif /* MALLOC_INSPECT_ALL */
-
-#if !NO_MALLINFO
-/*
-  mallinfo()
-  Returns (by copy) a struct containing various summary statistics:
-
-  arena:     current total non-mmapped bytes allocated from system
-  ordblks:   the number of free chunks
-  smblks:    always zero.
-  hblks:     current number of mmapped regions
-  hblkhd:    total bytes held in mmapped regions
-  usmblks:   the maximum total allocated space. This will be greater
-                than current total if trimming has occurred.
-  fsmblks:   always zero
-  uordblks:  current total allocated space (normal or mmapped)
-  fordblks:  total free space
-  keepcost:  the maximum number of bytes that could ideally be released
-               back to system via malloc_trim. ("ideally" means that
-               it ignores page restrictions etc.)
-
-  Because these fields are ints, but internal bookkeeping may
-  be kept as longs, the reported values may wrap around zero and
-  thus be inaccurate.
-*/
-DLMALLOC_EXPORT struct mallinfo dlmallinfo(void);
-#endif /* NO_MALLINFO */
-
-/*
-  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
-
-  independent_calloc is similar to calloc, but instead of returning a
-  single cleared space, it returns an array of pointers to n_elements
-  independent elements that can hold contents of size elem_size, each
-  of which starts out cleared, and can be independently freed,
-  realloc'ed etc. The elements are guaranteed to be adjacently
-  allocated (this is not guaranteed to occur with multiple callocs or
-  mallocs), which may also improve cache locality in some
-  applications.
-
-  The "chunks" argument is optional (i.e., may be null, which is
-  probably the most typical usage). If it is null, the returned array
-  is itself dynamically allocated and should also be freed when it is
-  no longer needed. Otherwise, the chunks array must be of at least
-  n_elements in length. It is filled in with the pointers to the
-  chunks.
-
-  In either case, independent_calloc returns this pointer array, or
-  null if the allocation failed.  If n_elements is zero and "chunks"
-  is null, it returns a chunk representing an array with zero elements
-  (which should be freed if not wanted).
-
-  Each element must be freed when it is no longer needed. This can be
-  done all at once using bulk_free.
-
-  independent_calloc simplifies and speeds up implementations of many
-  kinds of pools.  It may also be useful when constructing large data
-  structures that initially have a fixed number of fixed-sized nodes,
-  but the number is not known at compile time, and some of the nodes
-  may later need to be freed. For example:
-
-  struct Node { int item; struct Node* next; };
-
-  struct Node* build_list() {
-    struct Node** pool;
-    int n = read_number_of_nodes_needed();
-    if (n <= 0) return 0;
-    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
-    if (pool == 0) die();
-    // organize into a linked list...
-    struct Node* first = pool[0];
-    for (i = 0; i < n-1; ++i)
-      pool[i]->next = pool[i+1];
-    free(pool);     // Can now free the array (or not, if it is needed later)
-    return first;
-  }
-*/
-DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**);
-
-/*
-  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
-
-  independent_comalloc allocates, all at once, a set of n_elements
-  chunks with sizes indicated in the "sizes" array.    It returns
-  an array of pointers to these elements, each of which can be
-  independently freed, realloc'ed etc. The elements are guaranteed to
-  be adjacently allocated (this is not guaranteed to occur with
-  multiple callocs or mallocs), which may also improve cache locality
-  in some applications.
-
-  The "chunks" argument is optional (i.e., may be null). If it is null
-  the returned array is itself dynamically allocated and should also
-  be freed when it is no longer needed. Otherwise, the chunks array
-  must be of at least n_elements in length. It is filled in with the
-  pointers to the chunks.
-
-  In either case, independent_comalloc returns this pointer array, or
-  null if the allocation failed.  If n_elements is zero and chunks is
-  null, it returns a chunk representing an array with zero elements
-  (which should be freed if not wanted).
-
-  Each element must be freed when it is no longer needed. This can be
-  done all at once using bulk_free.
-
-  independent_comallac differs from independent_calloc in that each
-  element may have a different size, and also that it does not
-  automatically clear elements.
-
-  independent_comalloc can be used to speed up allocation in cases
-  where several structs or objects must always be allocated at the
-  same time.  For example:
-
-  struct Head { ... }
-  struct Foot { ... }
-
-  void send_message(char* msg) {
-    int msglen = strlen(msg);
-    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
-    void* chunks[3];
-    if (independent_comalloc(3, sizes, chunks) == 0)
-      die();
-    struct Head* head = (struct Head*)(chunks[0]);
-    char*        body = (char*)(chunks[1]);
-    struct Foot* foot = (struct Foot*)(chunks[2]);
-    // ...
-  }
-
-  In general though, independent_comalloc is worth using only for
-  larger values of n_elements. For small values, you probably won't
-  detect enough difference from series of malloc calls to bother.
-
-  Overuse of independent_comalloc can increase overall memory usage,
-  since it cannot reuse existing noncontiguous small chunks that
-  might be available for some of the elements.
-*/
-DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**);
-
-/*
-  bulk_free(void* array[], size_t n_elements)
-  Frees and clears (sets to null) each non-null pointer in the given
-  array.  This is likely to be faster than freeing them one-by-one.
-  If footers are used, pointers that have been allocated in different
-  mspaces are not freed or cleared, and the count of all such pointers
-  is returned.  For large arrays of pointers with poor locality, it
-  may be worthwhile to sort this array before calling bulk_free.
-*/
-DLMALLOC_EXPORT size_t  dlbulk_free(void**, size_t n_elements);
-
-/*
-  pvalloc(size_t n);
-  Equivalent to valloc(minimum-page-that-holds(n)), that is,
-  round up n to nearest pagesize.
- */
-DLMALLOC_EXPORT void*  dlpvalloc(size_t);
-
-/*
-  malloc_trim(size_t pad);
-
-  If possible, gives memory back to the system (via negative arguments
-  to sbrk) if there is unused memory at the `high' end of the malloc
-  pool or in unused MMAP segments. You can call this after freeing
-  large blocks of memory to potentially reduce the system-level memory
-  requirements of a program. However, it cannot guarantee to reduce
-  memory. Under some allocation patterns, some large free blocks of
-  memory will be locked between two used chunks, so they cannot be
-  given back to the system.
-
-  The `pad' argument to malloc_trim represents the amount of free
-  trailing space to leave untrimmed. If this argument is zero, only
-  the minimum amount of memory to maintain internal data structures
-  will be left. Non-zero arguments can be supplied to maintain enough
-  trailing space to service future expected allocations without having
-  to re-obtain memory from the system.
-
-  Malloc_trim returns 1 if it actually released any memory, else 0.
-*/
-DLMALLOC_EXPORT int  dlmalloc_trim(size_t);
-
-/*
-  malloc_stats();
-  Prints on stderr the amount of space obtained from the system (both
-  via sbrk and mmap), the maximum amount (which may be more than
-  current if malloc_trim and/or munmap got called), and the current
-  number of bytes allocated via malloc (or realloc, etc) but not yet
-  freed. Note that this is the number of bytes allocated, not the
-  number requested. It will be larger than the number requested
-  because of alignment and bookkeeping overhead. Because it includes
-  alignment wastage as being in use, this figure may be greater than
-  zero even when no user-level chunks are allocated.
-
-  The reported current and maximum system memory can be inaccurate if
-  a program makes other calls to system memory allocation functions
-  (normally sbrk) outside of malloc.
-
-  malloc_stats prints only the most commonly interesting statistics.
-  More information can be obtained by calling mallinfo.
-*/
-DLMALLOC_EXPORT void  dlmalloc_stats(void);
-
-/*
-  malloc_usable_size(void* p);
-
-  Returns the number of bytes you can actually use in
-  an allocated chunk, which may be more than you requested (although
-  often not) due to alignment and minimum size constraints.
-  You can use this many bytes without worrying about
-  overwriting other allocated objects. This is not a particularly great
-  programming practice. malloc_usable_size can be more useful in
-  debugging and assertions, for example:
-
-  p = malloc(n);
-  assert(malloc_usable_size(p) >= 256);
-*/
-size_t dlmalloc_usable_size(void*);
-
-#endif /* ONLY_MSPACES */
-
-#if MSPACES
-
-/*
-  mspace is an opaque type representing an independent
-  region of space that supports mspace_malloc, etc.
-*/
-typedef void* mspace;
-
-/*
-  create_mspace creates and returns a new independent space with the
-  given initial capacity, or, if 0, the default granularity size.  It
-  returns null if there is no system memory available to create the
-  space.  If argument locked is non-zero, the space uses a separate
-  lock to control access. The capacity of the space will grow
-  dynamically as needed to service mspace_malloc requests.  You can
-  control the sizes of incremental increases of this space by
-  compiling with a different DEFAULT_GRANULARITY or dynamically
-  setting with mallopt(M_GRANULARITY, value).
-*/
-DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked);
-
-/*
-  destroy_mspace destroys the given space, and attempts to return all
-  of its memory back to the system, returning the total number of
-  bytes freed. After destruction, the results of access to all memory
-  used by the space become undefined.
-*/
-DLMALLOC_EXPORT size_t destroy_mspace(mspace msp);
-
-/*
-  create_mspace_with_base uses the memory supplied as the initial base
-  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
-  space is used for bookkeeping, so the capacity must be at least this
-  large. (Otherwise 0 is returned.) When this initial space is
-  exhausted, additional memory will be obtained from the system.
-  Destroying this space will deallocate all additionally allocated
-  space (if possible) but not the initial base.
-*/
-DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked);
-
-/*
-  mspace_track_large_chunks controls whether requests for large chunks
-  are allocated in their own untracked mmapped regions, separate from
-  others in this mspace. By default large chunks are not tracked,
-  which reduces fragmentation. However, such chunks are not
-  necessarily released to the system upon destroy_mspace.  Enabling
-  tracking by setting to true may increase fragmentation, but avoids
-  leakage when relying on destroy_mspace to release all memory
-  allocated using this space.  The function returns the previous
-  setting.
-*/
-DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable);
-
-
-/*
-  mspace_malloc behaves as malloc, but operates within
-  the given space.
-*/
-DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes);
-
-/*
-  mspace_free behaves as free, but operates within
-  the given space.
-
-  If compiled with FOOTERS==1, mspace_free is not actually needed.
-  free may be called instead of mspace_free because freed chunks from
-  any space are handled by their originating spaces.
-*/
-DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem);
-
-/*
-  mspace_realloc behaves as realloc, but operates within
-  the given space.
-
-  If compiled with FOOTERS==1, mspace_realloc is not actually
-  needed.  realloc may be called instead of mspace_realloc because
-  realloced chunks from any space are handled by their originating
-  spaces.
-*/
-DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize);
-
-/*
-  mspace_calloc behaves as calloc, but operates within
-  the given space.
-*/
-DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
-
-/*
-  mspace_memalign behaves as memalign, but operates within
-  the given space.
-*/
-DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
-
-/*
-  mspace_independent_calloc behaves as independent_calloc, but
-  operates within the given space.
-*/
-DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements,
-                                 size_t elem_size, void* chunks[]);
-
-/*
-  mspace_independent_comalloc behaves as independent_comalloc, but
-  operates within the given space.
-*/
-DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements,
-                                   size_t sizes[], void* chunks[]);
-
-/*
-  mspace_footprint() returns the number of bytes obtained from the
-  system for this space.
-*/
-DLMALLOC_EXPORT size_t mspace_footprint(mspace msp);
-
-/*
-  mspace_max_footprint() returns the peak number of bytes obtained from the
-  system for this space.
-*/
-DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp);
-
-
-#if !NO_MALLINFO
-/*
-  mspace_mallinfo behaves as mallinfo, but reports properties of
-  the given space.
-*/
-DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp);
-#endif /* NO_MALLINFO */
-
-/*
-  malloc_usable_size(void* p) behaves the same as malloc_usable_size;
-*/
-DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem);
-
-/*
-  mspace_malloc_stats behaves as malloc_stats, but reports
-  properties of the given space.
-*/
-DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp);
-
-/*
-  mspace_trim behaves as malloc_trim, but
-  operates within the given space.
-*/
-DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad);
-
-/*
-  An alias for mallopt.
-*/
-DLMALLOC_EXPORT int mspace_mallopt(int, int);
-
-#endif /* MSPACES */
-
-#ifdef __cplusplus
-}  /* end of extern "C" */
-#endif /* __cplusplus */
-
-/*
-  ========================================================================
-  To make a fully customizable malloc.h header file, cut everything
-  above this line, put into file malloc.h, edit to suit, and #include it
-  on the next line, as well as in programs that use this malloc.
-  ========================================================================
-*/
-
-/* #include "malloc.h" */
-
-/*------------------------------ internal #includes ---------------------- */
-
-#ifdef _MSC_VER
-#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
-#endif /* _MSC_VER */
-#if !NO_MALLOC_STATS
-#include <stdio.h>       /* for printing in malloc_stats */
-#endif /* NO_MALLOC_STATS */
-#ifndef LACKS_ERRNO_H
-#include <errno.h>       /* for MALLOC_FAILURE_ACTION */
-#endif /* LACKS_ERRNO_H */
-#ifdef DEBUG
-#if ABORT_ON_ASSERT_FAILURE
-#undef assert
-#define assert(x) if(!(x)) ABORT
-#else /* ABORT_ON_ASSERT_FAILURE */
-#include <assert.h>
-#endif /* ABORT_ON_ASSERT_FAILURE */
-#else  /* DEBUG */
-#ifndef assert
-#define assert(x)
-#endif
-#define DEBUG 0
-#endif /* DEBUG */
-#if !defined(WIN32) && !defined(LACKS_TIME_H)
-#include <time.h>        /* for magic initialization */
-#endif /* WIN32 */
-#ifndef LACKS_STDLIB_H
-#include <stdlib.h>      /* for abort() */
-#endif /* LACKS_STDLIB_H */
-#ifndef LACKS_STRING_H
-#include <string.h>      /* for memset etc */
-#endif  /* LACKS_STRING_H */
-#if USE_BUILTIN_FFS
-#ifndef LACKS_STRINGS_H
-#include <strings.h>     /* for ffs */
-#endif /* LACKS_STRINGS_H */
-#endif /* USE_BUILTIN_FFS */
-#if HAVE_MMAP
-#ifndef LACKS_SYS_MMAN_H
-/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */
-#if (defined(linux) && !defined(__USE_GNU))
-#define __USE_GNU 1
-#include <sys/mman.h>    /* for mmap */
-#undef __USE_GNU
-#else
-#include <sys/mman.h>    /* for mmap */
-#endif /* linux */
-#endif /* LACKS_SYS_MMAN_H */
-#ifndef LACKS_FCNTL_H
-#include <fcntl.h>
-#endif /* LACKS_FCNTL_H */
-#endif /* HAVE_MMAP */
-#ifndef LACKS_UNISTD_H
-#include <unistd.h>     /* for sbrk, sysconf */
-#else /* LACKS_UNISTD_H */
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
-extern void*     sbrk(ptrdiff_t);
-#endif /* FreeBSD etc */
-#endif /* LACKS_UNISTD_H */
-
-/* Declarations for locking */
-#if USE_LOCKS
-#ifndef WIN32
-#if defined (__SVR4) && defined (__sun)  /* solaris */
-#include <thread.h>
-#elif !defined(LACKS_SCHED_H)
-#include <sched.h>
-#endif /* solaris or LACKS_SCHED_H */
-#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS
-#include <pthread.h>
-#endif /* USE_RECURSIVE_LOCKS ... */
-#elif defined(_MSC_VER)
-#ifndef _M_AMD64
-/* These are already defined on AMD64 builds */
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
-LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* _M_AMD64 */
-#pragma intrinsic (_InterlockedCompareExchange)
-#pragma intrinsic (_InterlockedExchange)
-#define interlockedcompareexchange _InterlockedCompareExchange
-#define interlockedexchange _InterlockedExchange
-#elif defined(WIN32) && defined(__GNUC__)
-#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b)
-#define interlockedexchange __sync_lock_test_and_set
-#endif /* Win32 */
-#else /* USE_LOCKS */
-#endif /* USE_LOCKS */
-
-#ifndef LOCK_AT_FORK
-#define LOCK_AT_FORK 0
-#endif
-
-/* Declarations for bit scanning on win32 */
-#if defined(_MSC_VER) && _MSC_VER>=1300
-#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
-unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#define BitScanForward _BitScanForward
-#define BitScanReverse _BitScanReverse
-#pragma intrinsic(_BitScanForward)
-#pragma intrinsic(_BitScanReverse)
-#endif /* BitScanForward */
-#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
-
-#ifndef WIN32
-#ifndef malloc_getpagesize
-#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
-#    ifndef _SC_PAGE_SIZE
-#      define _SC_PAGE_SIZE _SC_PAGESIZE
-#    endif
-#  endif
-#  ifdef _SC_PAGE_SIZE
-#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
-#  else
-#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
-       extern size_t getpagesize();
-#      define malloc_getpagesize getpagesize()
-#    else
-#      ifdef WIN32 /* use supplied emulation of getpagesize */
-#        define malloc_getpagesize getpagesize()
-#      else
-#        ifndef LACKS_SYS_PARAM_H
-#          include <sys/param.h>
-#        endif
-#        ifdef EXEC_PAGESIZE
-#          define malloc_getpagesize EXEC_PAGESIZE
-#        else
-#          ifdef NBPG
-#            ifndef CLSIZE
-#              define malloc_getpagesize NBPG
-#            else
-#              define malloc_getpagesize (NBPG * CLSIZE)
-#            endif
-#          else
-#            ifdef NBPC
-#              define malloc_getpagesize NBPC
-#            else
-#              ifdef PAGESIZE
-#                define malloc_getpagesize PAGESIZE
-#              else /* just guess */
-#                define malloc_getpagesize ((size_t)4096U)
-#              endif
-#            endif
-#          endif
-#        endif
-#      endif
-#    endif
-#  endif
-#endif
-#endif
-
-/* ------------------- size_t and alignment properties -------------------- */
-
-/* The byte and bit size of a size_t */
-#define SIZE_T_SIZE         (sizeof(size_t))
-#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)
-
-/* Some constants coerced to size_t */
-/* Annoying but necessary to avoid errors on some platforms */
-#define SIZE_T_ZERO         ((size_t)0)
-#define SIZE_T_ONE          ((size_t)1)
-#define SIZE_T_TWO          ((size_t)2)
-#define SIZE_T_FOUR         ((size_t)4)
-#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)
-#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)
-#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
-#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)
-
-/* The bit mask value corresponding to MALLOC_ALIGNMENT */
-#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)
-
-/* True if address a has acceptable alignment */
-#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
-
-/* the number of bytes to offset an address to align it */
-#define align_offset(A)\
- ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
-  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
-
-/* -------------------------- MMAP preliminaries ------------------------- */
-
-/*
-   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
-   checks to fail so compiler optimizer can delete code rather than
-   using so many "#if"s.
-*/
-
-
-/* MORECORE and MMAP must return MFAIL on failure */
-#define MFAIL                ((void*)(MAX_SIZE_T))
-#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */
-
-#if HAVE_MMAP
-
-#ifndef WIN32
-#define MUNMAP_DEFAULT(a, s)  munmap((a), (s))
-#define MMAP_PROT            (PROT_READ|PROT_WRITE)
-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
-#define MAP_ANONYMOUS        MAP_ANON
-#endif /* MAP_ANON */
-#ifdef MAP_ANONYMOUS
-#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)
-#define MMAP_DEFAULT(s)       mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
-#else /* MAP_ANONYMOUS */
-/*
-   Nearly all versions of mmap support MAP_ANONYMOUS, so the following
-   is unlikely to be needed, but is supplied just in case.
-*/
-#define MMAP_FLAGS           (MAP_PRIVATE)
-static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
-#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
-           (dev_zero_fd = open("/dev/zero", O_RDWR), \
-            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
-            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
-#endif /* MAP_ANONYMOUS */
-
-#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
-
-#else /* WIN32 */
-
-/* Win32 MMAP via VirtualAlloc */
-static FORCEINLINE void* win32mmap(size_t size) {
-  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
-  return (ptr != 0)? ptr: MFAIL;
-}
-
-/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
-static FORCEINLINE void* win32direct_mmap(size_t size) {
-  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
-                           PAGE_READWRITE);
-  return (ptr != 0)? ptr: MFAIL;
-}
-
-/* This function supports releasing coalesed segments */
-static FORCEINLINE int win32munmap(void* ptr, size_t size) {
-  MEMORY_BASIC_INFORMATION minfo;
-  char* cptr = (char*)ptr;
-  while (size) {
-    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
-      return -1;
-    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
-        minfo.State != MEM_COMMIT || minfo.RegionSize > size)
-      return -1;
-    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
-      return -1;
-    cptr += minfo.RegionSize;
-    size -= minfo.RegionSize;
-  }
-  return 0;
-}
-
-#define MMAP_DEFAULT(s)             win32mmap(s)
-#define MUNMAP_DEFAULT(a, s)        win32munmap((a), (s))
-#define DIRECT_MMAP_DEFAULT(s)      win32direct_mmap(s)
-#endif /* WIN32 */
-#endif /* HAVE_MMAP */
-
-#if HAVE_MREMAP
-#ifndef WIN32
-#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
-#endif /* WIN32 */
-#endif /* HAVE_MREMAP */
-
-/**
- * Define CALL_MORECORE
- */
-#if HAVE_MORECORE
-    #ifdef MORECORE
-        #define CALL_MORECORE(S)    MORECORE(S)
-    #else  /* MORECORE */
-        #define CALL_MORECORE(S)    MORECORE_DEFAULT(S)
-    #endif /* MORECORE */
-#else  /* HAVE_MORECORE */
-    #define CALL_MORECORE(S)        MFAIL
-#endif /* HAVE_MORECORE */
-
-/**
- * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
- */
-#if HAVE_MMAP
-    #define USE_MMAP_BIT            (SIZE_T_ONE)
-
-    #ifdef MMAP
-        #define CALL_MMAP(s)        MMAP(s)
-    #else /* MMAP */
-        #define CALL_MMAP(s)        MMAP_DEFAULT(s)
-    #endif /* MMAP */
-    #ifdef MUNMAP
-        #define CALL_MUNMAP(a, s)   MUNMAP((a), (s))
-    #else /* MUNMAP */
-        #define CALL_MUNMAP(a, s)   MUNMAP_DEFAULT((a), (s))
-    #endif /* MUNMAP */
-    #ifdef DIRECT_MMAP
-        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
-    #else /* DIRECT_MMAP */
-        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
-    #endif /* DIRECT_MMAP */
-#else  /* HAVE_MMAP */
-    #define USE_MMAP_BIT            (SIZE_T_ZERO)
-
-    #define MMAP(s)                 MFAIL
-    #define MUNMAP(a, s)            (-1)
-    #define DIRECT_MMAP(s)          MFAIL
-    #define CALL_DIRECT_MMAP(s)     DIRECT_MMAP(s)
-    #define CALL_MMAP(s)            MMAP(s)
-    #define CALL_MUNMAP(a, s)       MUNMAP((a), (s))
-#endif /* HAVE_MMAP */
-
-/**
- * Define CALL_MREMAP
- */
-#if HAVE_MMAP && HAVE_MREMAP
-    #ifdef MREMAP
-        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
-    #else /* MREMAP */
-        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
-    #endif /* MREMAP */
-#else  /* HAVE_MMAP && HAVE_MREMAP */
-    #define CALL_MREMAP(addr, osz, nsz, mv)     MFAIL
-#endif /* HAVE_MMAP && HAVE_MREMAP */
-
-/* mstate bit set if continguous morecore disabled or failed */
-#define USE_NONCONTIGUOUS_BIT (4U)
-
-/* segment bit set in create_mspace_with_base */
-#define EXTERN_BIT            (8U)
-
-
-/* --------------------------- Lock preliminaries ------------------------ */
-
-/*
-  When locks are defined, there is one global lock, plus
-  one per-mspace lock.
-
-  The global lock_ensures that mparams.magic and other unique
-  mparams values are initialized only once. It also protects
-  sequences of calls to MORECORE.  In many cases sys_alloc requires
-  two calls, that should not be interleaved with calls by other
-  threads.  This does not protect against direct calls to MORECORE
-  by other threads not using this lock, so there is still code to
-  cope the best we can on interference.
-
-  Per-mspace locks surround calls to malloc, free, etc.
-  By default, locks are simple non-reentrant mutexes.
-
-  Because lock-protected regions generally have bounded times, it is
-  OK to use the supplied simple spinlocks. Spinlocks are likely to
-  improve performance for lightly contended applications, but worsen
-  performance under heavy contention.
-
-  If USE_LOCKS is > 1, the definitions of lock routines here are
-  bypassed, in which case you will need to define the type MLOCK_T,
-  and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK
-  and TRY_LOCK.  You must also declare a
-    static MLOCK_T malloc_global_mutex = { initialization values };.
-
-*/
-
-#if !USE_LOCKS
-#define USE_LOCK_BIT               (0U)
-#define INITIAL_LOCK(l)            (0)
-#define DESTROY_LOCK(l)            (0)
-#define ACQUIRE_MALLOC_GLOBAL_LOCK()
-#define RELEASE_MALLOC_GLOBAL_LOCK()
-
-#else
-#if USE_LOCKS > 1
-/* -----------------------  User-defined locks ------------------------ */
-/* Define your own lock implementation here */
-/* #define INITIAL_LOCK(lk)  ... */
-/* #define DESTROY_LOCK(lk)  ... */
-/* #define ACQUIRE_LOCK(lk)  ... */
-/* #define RELEASE_LOCK(lk)  ... */
-/* #define TRY_LOCK(lk) ... */
-/* static MLOCK_T malloc_global_mutex = ... */
-
-#elif USE_SPIN_LOCKS
-
-/* First, define CAS_LOCK and CLEAR_LOCK on ints */
-/* Note CAS_LOCK defined to return 0 on success */
-
-#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
-#define CAS_LOCK(sl)     __sync_lock_test_and_set(sl, 1)
-#define CLEAR_LOCK(sl)   __sync_lock_release(sl)
-
-#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
-/* Custom spin locks for older gcc on x86 */
-static FORCEINLINE int x86_cas_lock(int *sl) {
-  int ret;
-  int val = 1;
-  int cmp = 0;
-  __asm__ __volatile__  ("lock; cmpxchgl %1, %2"
-                         : "=a" (ret)
-                         : "r" (val), "m" (*(sl)), "0"(cmp)
-                         : "memory", "cc");
-  return ret;
-}
-
-static FORCEINLINE void x86_clear_lock(int* sl) {
-  assert(*sl != 0);
-  int prev = 0;
-  int ret;
-  __asm__ __volatile__ ("lock; xchgl %0, %1"
-                        : "=r" (ret)
-                        : "m" (*(sl)), "0"(prev)
-                        : "memory");
-}
-
-#define CAS_LOCK(sl)     x86_cas_lock(sl)
-#define CLEAR_LOCK(sl)   x86_clear_lock(sl)
-
-#else /* Win32 MSC */
-#define CAS_LOCK(sl)     interlockedexchange(sl, (LONG)1)
-#define CLEAR_LOCK(sl)   interlockedexchange (sl, (LONG)0)
-
-#endif /* ... gcc spins locks ... */
-
-/* How to yield for a spin lock */
-#define SPINS_PER_YIELD       63
-#if defined(_MSC_VER)
-#define SLEEP_EX_DURATION     50 /* delay for yield/sleep */
-#define SPIN_LOCK_YIELD  SleepEx(SLEEP_EX_DURATION, FALSE)
-#elif defined (__SVR4) && defined (__sun) /* solaris */
-#define SPIN_LOCK_YIELD   thr_yield();
-#elif !defined(LACKS_SCHED_H)
-#define SPIN_LOCK_YIELD   sched_yield();
-#else
-#define SPIN_LOCK_YIELD
-#endif /* ... yield ... */
-
-#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0
-/* Plain spin locks use single word (embedded in malloc_states) */
-static int spin_acquire_lock(int *sl) {
-  int spins = 0;
-  while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) {
-    if ((++spins & SPINS_PER_YIELD) == 0) {
-      SPIN_LOCK_YIELD;
-    }
-  }
-  return 0;
-}
-
-#define MLOCK_T               int
-#define TRY_LOCK(sl)          !CAS_LOCK(sl)
-#define RELEASE_LOCK(sl)      CLEAR_LOCK(sl)
-#define ACQUIRE_LOCK(sl)      (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0)
-#define INITIAL_LOCK(sl)      (*sl = 0)
-#define DESTROY_LOCK(sl)      (0)
-static MLOCK_T malloc_global_mutex = 0;
-
-#else /* USE_RECURSIVE_LOCKS */
-/* types for lock owners */
-#ifdef WIN32
-#define THREAD_ID_T           DWORD
-#define CURRENT_THREAD        GetCurrentThreadId()
-#define EQ_OWNER(X,Y)         ((X) == (Y))
-#else
-/*
-  Note: the following assume that pthread_t is a type that can be
-  initialized to (casted) zero. If this is not the case, you will need to
-  somehow redefine these or not use spin locks.
-*/
-#define THREAD_ID_T           pthread_t
-#define CURRENT_THREAD        pthread_self()
-#define EQ_OWNER(X,Y)         pthread_equal(X, Y)
-#endif
-
-struct malloc_recursive_lock {
-  int sl;
-  unsigned int c;
-  THREAD_ID_T threadid;
-};
-
-#define MLOCK_T  struct malloc_recursive_lock
-static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0};
-
-static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) {
-  assert(lk->sl != 0);
-  if (--lk->c == 0) {
-    CLEAR_LOCK(&lk->sl);
-  }
-}
-
-static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) {
-  THREAD_ID_T mythreadid = CURRENT_THREAD;
-  int spins = 0;
-  for (;;) {
-    if (*((volatile int *)(&lk->sl)) == 0) {
-      if (!CAS_LOCK(&lk->sl)) {
-        lk->threadid = mythreadid;
-        lk->c = 1;
-        return 0;
-      }
-    }
-    else if (EQ_OWNER(lk->threadid, mythreadid)) {
-      ++lk->c;
-      return 0;
-    }
-    if ((++spins & SPINS_PER_YIELD) == 0) {
-      SPIN_LOCK_YIELD;
-    }
-  }
-}
-
-static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) {
-  THREAD_ID_T mythreadid = CURRENT_THREAD;
-  if (*((volatile int *)(&lk->sl)) == 0) {
-    if (!CAS_LOCK(&lk->sl)) {
-      lk->threadid = mythreadid;
-      lk->c = 1;
-      return 1;
-    }
-  }
-  else if (EQ_OWNER(lk->threadid, mythreadid)) {
-    ++lk->c;
-    return 1;
-  }
-  return 0;
-}
-
-#define RELEASE_LOCK(lk)      recursive_release_lock(lk)
-#define TRY_LOCK(lk)          recursive_try_lock(lk)
-#define ACQUIRE_LOCK(lk)      recursive_acquire_lock(lk)
-#define INITIAL_LOCK(lk)      ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0)
-#define DESTROY_LOCK(lk)      (0)
-#endif /* USE_RECURSIVE_LOCKS */
-
-#elif defined(WIN32) /* Win32 critical sections */
-#define MLOCK_T               CRITICAL_SECTION
-#define ACQUIRE_LOCK(lk)      (EnterCriticalSection(lk), 0)
-#define RELEASE_LOCK(lk)      LeaveCriticalSection(lk)
-#define TRY_LOCK(lk)          TryEnterCriticalSection(lk)
-#define INITIAL_LOCK(lk)      (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000))
-#define DESTROY_LOCK(lk)      (DeleteCriticalSection(lk), 0)
-#define NEED_GLOBAL_LOCK_INIT
-
-static MLOCK_T malloc_global_mutex;
-static volatile LONG malloc_global_mutex_status;
-
-/* Use spin loop to initialize global lock */
-static void init_malloc_global_mutex() {
-  for (;;) {
-    long stat = malloc_global_mutex_status;
-    if (stat > 0)
-      return;
-    /* transition to < 0 while initializing, then to > 0) */
-    if (stat == 0 &&
-        interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) {
-      InitializeCriticalSection(&malloc_global_mutex);
-      interlockedexchange(&malloc_global_mutex_status, (LONG)1);
-      return;
-    }
-    SleepEx(0, FALSE);
-  }
-}
-
-#else /* pthreads-based locks */
-#define MLOCK_T               pthread_mutex_t
-#define ACQUIRE_LOCK(lk)      pthread_mutex_lock(lk)
-#define RELEASE_LOCK(lk)      pthread_mutex_unlock(lk)
-#define TRY_LOCK(lk)          (!pthread_mutex_trylock(lk))
-#define INITIAL_LOCK(lk)      pthread_init_lock(lk)
-#define DESTROY_LOCK(lk)      pthread_mutex_destroy(lk)
-
-#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE)
-/* Cope with old-style linux recursive lock initialization by adding */
-/* skipped internal declaration from pthread.h */
-extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
-                                              int __kind));
-#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
-#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
-#endif /* USE_RECURSIVE_LOCKS ... */
-
-static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static int pthread_init_lock (MLOCK_T *lk) {
-  pthread_mutexattr_t attr;
-  if (pthread_mutexattr_init(&attr)) return 1;
-#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0
-  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
-#endif
-  if (pthread_mutex_init(lk, &attr)) return 1;
-  if (pthread_mutexattr_destroy(&attr)) return 1;
-  return 0;
-}
-
-#endif /* ... lock types ... */
-
-/* Common code for all lock types */
-#define USE_LOCK_BIT               (2U)
-
-#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK
-#define ACQUIRE_MALLOC_GLOBAL_LOCK()  ACQUIRE_LOCK(&malloc_global_mutex);
-#endif
-
-#ifndef RELEASE_MALLOC_GLOBAL_LOCK
-#define RELEASE_MALLOC_GLOBAL_LOCK()  RELEASE_LOCK(&malloc_global_mutex);
-#endif
-
-#endif /* USE_LOCKS */
-
-/* -----------------------  Chunk representations ------------------------ */
-
-/*
-  (The following includes lightly edited explanations by Colin Plumb.)
-
-  The malloc_chunk declaration below is misleading (but accurate and
-  necessary).  It declares a "view" into memory allowing access to
-  necessary fields at known offsets from a given base.
-
-  Chunks of memory are maintained using a `boundary tag' method as
-  originally described by Knuth.  (See the paper by Paul Wilson
-  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
-  techniques.)  Sizes of free chunks are stored both in the front of
-  each chunk and at the end.  This makes consolidating fragmented
-  chunks into bigger chunks fast.  The head fields also hold bits
-  representing whether chunks are free or in use.
-
-  Here are some pictures to make it clearer.  They are "exploded" to
-  show that the state of a chunk can be thought of as extending from
-  the high 31 bits of the head field of its header through the
-  prev_foot and PINUSE_BIT bit of the following chunk header.
-
-  A chunk that's in use looks like:
-
-   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-           | Size of previous chunk (if P = 0)                             |
-           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
-         | Size of this chunk                                         1| +-+
-   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         |                                                               |
-         +-                                                             -+
-         |                                                               |
-         +-                                                             -+
-         |                                                               :
-         +-      size - sizeof(size_t) available payload bytes          -+
-         :                                                               |
- chunk-> +-                                                             -+
-         |                                                               |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
-       | Size of next chunk (may or may not be in use)               | +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-    And if it's free, it looks like this:
-
-   chunk-> +-                                                             -+
-           | User payload (must be in use, or we would have merged!)       |
-           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
-         | Size of this chunk                                         0| +-+
-   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         | Next pointer                                                  |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         | Prev pointer                                                  |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         |                                                               :
-         +-      size - sizeof(struct chunk) unused bytes               -+
-         :                                                               |
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-         | Size of this chunk                                            |
-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
-       | Size of next chunk (must be in use, or we would have merged)| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |                                                               :
-       +- User payload                                                -+
-       :                                                               |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-                                                                     |0|
-                                                                     +-+
-  Note that since we always merge adjacent free chunks, the chunks
-  adjacent to a free chunk must be in use.
-
-  Given a pointer to a chunk (which can be derived trivially from the
-  payload pointer) we can, in O(1) time, find out whether the adjacent
-  chunks are free, and if so, unlink them from the lists that they
-  are on and merge them with the current chunk.
-
-  Chunks always begin on even word boundaries, so the mem portion
-  (which is returned to the user) is also on an even word boundary, and
-  thus at least double-word aligned.
-
-  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
-  chunk size (which is always a multiple of two words), is an in-use
-  bit for the *previous* chunk.  If that bit is *clear*, then the
-  word before the current chunk size contains the previous chunk
-  size, and can be used to find the front of the previous chunk.
-  The very first chunk allocated always has this bit set, preventing
-  access to non-existent (or non-owned) memory. If pinuse is set for
-  any given chunk, then you CANNOT determine the size of the
-  previous chunk, and might even get a memory addressing fault when
-  trying to do so.
-
-  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
-  the chunk size redundantly records whether the current chunk is
-  inuse (unless the chunk is mmapped). This redundancy enables usage
-  checks within free and realloc, and reduces indirection when freeing
-  and consolidating chunks.
-
-  Each freshly allocated chunk must have both cinuse and pinuse set.
-  That is, each allocated chunk borders either a previously allocated
-  and still in-use chunk, or the base of its memory arena. This is
-  ensured by making all allocations from the `lowest' part of any
-  found chunk.  Further, no free chunk physically borders another one,
-  so each free chunk is known to be preceded and followed by either
-  inuse chunks or the ends of memory.
-
-  Note that the `foot' of the current chunk is actually represented
-  as the prev_foot of the NEXT chunk. This makes it easier to
-  deal with alignments etc but can be very confusing when trying
-  to extend or adapt this code.
-
-  The exceptions to all this are
-
-     1. The special chunk `top' is the top-most available chunk (i.e.,
-        the one bordering the end of available memory). It is treated
-        specially.  Top is never included in any bin, is used only if
-        no other chunk is available, and is released back to the
-        system if it is very large (see M_TRIM_THRESHOLD).  In effect,
-        the top chunk is treated as larger (and thus less well
-        fitting) than any other available chunk.  The top chunk
-        doesn't update its trailing size field since there is no next
-        contiguous chunk that would have to index off it. However,
-        space is still allocated for it (TOP_FOOT_SIZE) to enable
-        separation or merging when space is extended.
-
-     3. Chunks allocated via mmap, have both cinuse and pinuse bits
-        cleared in their head fields.  Because they are allocated
-        one-by-one, each must carry its own prev_foot field, which is
-        also used to hold the offset this chunk has within its mmapped
-        region, which is needed to preserve alignment. Each mmapped
-        chunk is trailed by the first two fields of a fake next-chunk
-        for sake of usage checks.
-
-*/
-
-struct malloc_chunk {
-  size_t               prev_foot;  /* Size of previous chunk (if free).  */
-  size_t               head;       /* Size and inuse bits. */
-  struct malloc_chunk* fd;         /* double links -- used only if free. */
-  struct malloc_chunk* bk;
-};
-
-typedef struct malloc_chunk  mchunk;
-typedef struct malloc_chunk* mchunkptr;
-typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */
-typedef unsigned int bindex_t;         /* Described below */
-typedef unsigned int binmap_t;         /* Described below */
-typedef unsigned int flag_t;           /* The type of various bit flag sets */
-
-/* ------------------- Chunks sizes and alignments ----------------------- */
-
-#define MCHUNK_SIZE         (sizeof(mchunk))
-
-#if FOOTERS
-#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)
-#else /* FOOTERS */
-#define CHUNK_OVERHEAD      (SIZE_T_SIZE)
-#endif /* FOOTERS */
-
-/* MMapped chunks need a second word of overhead ... */
-#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
-/* ... and additional padding for fake next-chunk at foot */
-#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)
-
-/* The smallest size we can malloc is an aligned minimal chunk */
-#define MIN_CHUNK_SIZE\
-  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* conversion from malloc headers to user pointers, and back */
-#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))
-#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
-/* chunk associated with aligned address A */
-#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))
-
-/* Bounds on request (not chunk) sizes. */
-#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)
-#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
-
-/* pad request bytes into a usable size */
-#define pad_request(req) \
-   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* pad request, checking for minimum (but not maximum) */
-#define request2size(req) \
-  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
-
-
-/* ------------------ Operations on head and foot fields ----------------- */
-
-/*
-  The head field of a chunk is or'ed with PINUSE_BIT when previous
-  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
-  use, unless mmapped, in which case both bits are cleared.
-
-  FLAG4_BIT is not used by this malloc, but might be useful in extensions.
-*/
-
-#define PINUSE_BIT          (SIZE_T_ONE)
-#define CINUSE_BIT          (SIZE_T_TWO)
-#define FLAG4_BIT           (SIZE_T_FOUR)
-#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)
-#define FLAG_BITS           (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
-
-/* Head value for fenceposts */
-#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)
-
-/* extraction of fields from head words */
-#define cinuse(p)           ((p)->head & CINUSE_BIT)
-#define pinuse(p)           ((p)->head & PINUSE_BIT)
-#define flag4inuse(p)       ((p)->head & FLAG4_BIT)
-#define is_inuse(p)         (((p)->head & INUSE_BITS) != PINUSE_BIT)
-#define is_mmapped(p)       (((p)->head & INUSE_BITS) == 0)
-
-#define chunksize(p)        ((p)->head & ~(FLAG_BITS))
-
-#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)
-#define set_flag4(p)        ((p)->head |= FLAG4_BIT)
-#define clear_flag4(p)      ((p)->head &= ~FLAG4_BIT)
-
-/* Treat space at ptr +/- offset as a chunk */
-#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
-#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
-
-/* Ptr to next or previous physical malloc_chunk. */
-#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
-#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
-
-/* extract next chunk's pinuse bit */
-#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)
-
-/* Get/set size at footer */
-#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)
-#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
-
-/* Set size, pinuse bit, and foot */
-#define set_size_and_pinuse_of_free_chunk(p, s)\
-  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
-
-/* Set size, pinuse bit, foot, and clear next pinuse */
-#define set_free_with_pinuse(p, s, n)\
-  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
-
-/* Get the internal overhead associated with chunk p */
-#define overhead_for(p)\
- (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
-
-/* Return true if malloced space is not necessarily cleared */
-#if MMAP_CLEARS
-#define calloc_must_clear(p) (!is_mmapped(p))
-#else /* MMAP_CLEARS */
-#define calloc_must_clear(p) (1)
-#endif /* MMAP_CLEARS */
-
-/* ---------------------- Overlaid data structures ----------------------- */
-
-/*
-  When chunks are not in use, they are treated as nodes of either
-  lists or trees.
-
-  "Small"  chunks are stored in circular doubly-linked lists, and look
-  like this:
-
-    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Size of previous chunk                            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `head:' |             Size of chunk, in bytes                         |P|
-      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Forward pointer to next chunk in list             |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Back pointer to previous chunk in list            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Unused space (may be 0 bytes long)                .
-            .                                                               .
-            .                                                               |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `foot:' |             Size of chunk, in bytes                           |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-  Larger chunks are kept in a form of bitwise digital trees (aka
-  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for
-  free chunks greater than 256 bytes, their size doesn't impose any
-  constraints on user chunk sizes.  Each node looks like:
-
-    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Size of previous chunk                            |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `head:' |             Size of chunk, in bytes                         |P|
-      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Forward pointer to next chunk of same size        |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Back pointer to previous chunk of same size       |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Pointer to left child (child[0])                  |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Pointer to right child (child[1])                 |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Pointer to parent                                 |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             bin index of this chunk                           |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-            |             Unused space                                      .
-            .                                                               |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    `foot:' |             Size of chunk, in bytes                           |
-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
-  of the same size are arranged in a circularly-linked list, with only
-  the oldest chunk (the next to be used, in our FIFO ordering)
-  actually in the tree.  (Tree members are distinguished by a non-null
-  parent pointer.)  If a chunk with the same size an an existing node
-  is inserted, it is linked off the existing node using pointers that
-  work in the same way as fd/bk pointers of small chunks.
-
-  Each tree contains a power of 2 sized range of chunk sizes (the
-  smallest is 0x100 <= x < 0x180), which is is divided in half at each
-  tree level, with the chunks in the smaller half of the range (0x100
-  <= x < 0x140 for the top nose) in the left subtree and the larger
-  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
-  done by inspecting individual bits.
-
-  Using these rules, each node's left subtree contains all smaller
-  sizes than its right subtree.  However, the node at the root of each
-  subtree has no particular ordering relationship to either.  (The
-  dividing line between the subtree sizes is based on trie relation.)
-  If we remove the last chunk of a given size from the interior of the
-  tree, we need to replace it with a leaf node.  The tree ordering
-  rules permit a node to be replaced by any leaf below it.
-
-  The smallest chunk in a tree (a common operation in a best-fit
-  allocator) can be found by walking a path to the leftmost leaf in
-  the tree.  Unlike a usual binary tree, where we follow left child
-  pointers until we reach a null, here we follow the right child
-  pointer any time the left one is null, until we reach a leaf with
-  both child pointers null. The smallest chunk in the tree will be
-  somewhere along that path.
-
-  The worst case number of steps to add, find, or remove a node is
-  bounded by the number of bits differentiating chunks within
-  bins. Under current bin calculations, this ranges from 6 up to 21
-  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
-  is of course much better.
-*/
-
-struct malloc_tree_chunk {
-  /* The first four fields must be compatible with malloc_chunk */
-  size_t                    prev_foot;
-  size_t                    head;
-  struct malloc_tree_chunk* fd;
-  struct malloc_tree_chunk* bk;
-
-  struct malloc_tree_chunk* child[2];
-  struct malloc_tree_chunk* parent;
-  bindex_t                  index;
-};
-
-typedef struct malloc_tree_chunk  tchunk;
-typedef struct malloc_tree_chunk* tchunkptr;
-typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
-
-/* A little helper macro for trees */
-#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
-
-/* ----------------------------- Segments -------------------------------- */
-
-/*
-  Each malloc space may include non-contiguous segments, held in a
-  list headed by an embedded malloc_segment record representing the
-  top-most space. Segments also include flags holding properties of
-  the space. Large chunks that are directly allocated by mmap are not
-  included in this list. They are instead independently created and
-  destroyed without otherwise keeping track of them.
-
-  Segment management mainly comes into play for spaces allocated by
-  MMAP.  Any call to MMAP might or might not return memory that is
-  adjacent to an existing segment.  MORECORE normally contiguously
-  extends the current space, so this space is almost always adjacent,
-  which is simpler and faster to deal with. (This is why MORECORE is
-  used preferentially to MMAP when both are available -- see
-  sys_alloc.)  When allocating using MMAP, we don't use any of the
-  hinting mechanisms (inconsistently) supported in various
-  implementations of unix mmap, or distinguish reserving from
-  committing memory. Instead, we just ask for space, and exploit
-  contiguity when we get it.  It is probably possible to do
-  better than this on some systems, but no general scheme seems
-  to be significantly better.
-
-  Management entails a simpler variant of the consolidation scheme
-  used for chunks to reduce fragmentation -- new adjacent memory is
-  normally prepended or appended to an existing segment. However,
-  there are limitations compared to chunk consolidation that mostly
-  reflect the fact that segment processing is relatively infrequent
-  (occurring only when getting memory from system) and that we
-  don't expect to have huge numbers of segments:
-
-  * Segments are not indexed, so traversal requires linear scans.  (It
-    would be possible to index these, but is not worth the extra
-    overhead and complexity for most programs on most platforms.)
-  * New segments are only appended to old ones when holding top-most
-    memory; if they cannot be prepended to others, they are held in
-    different segments.
-
-  Except for the top-most segment of an mstate, each segment record
-  is kept at the tail of its segment. Segments are added by pushing
-  segment records onto the list headed by &mstate.seg for the
-  containing mstate.
-
-  Segment flags control allocation/merge/deallocation policies:
-  * If EXTERN_BIT set, then we did not allocate this segment,
-    and so should not try to deallocate or merge with others.
-    (This currently holds only for the initial segment passed
-    into create_mspace_with_base.)
-  * If USE_MMAP_BIT set, the segment may be merged with
-    other surrounding mmapped segments and trimmed/de-allocated
-    using munmap.
-  * If neither bit is set, then the segment was obtained using
-    MORECORE so can be merged with surrounding MORECORE'd segments
-    and deallocated/trimmed using MORECORE with negative arguments.
-*/
-
-struct malloc_segment {
-  char*        base;             /* base address */
-  size_t       size;             /* allocated size */
-  struct malloc_segment* next;   /* ptr to next segment */
-  flag_t       sflags;           /* mmap and extern flag */
-};
-
-#define is_mmapped_segment(S)  ((S)->sflags & USE_MMAP_BIT)
-#define is_extern_segment(S)   ((S)->sflags & EXTERN_BIT)
-
-typedef struct malloc_segment  msegment;
-typedef struct malloc_segment* msegmentptr;
-
-/* ---------------------------- malloc_state ----------------------------- */
-
-/*
-   A malloc_state holds all of the bookkeeping for a space.
-   The main fields are:
-
-  Top
-    The topmost chunk of the currently active segment. Its size is
-    cached in topsize.  The actual size of topmost space is
-    topsize+TOP_FOOT_SIZE, which includes space reserved for adding
-    fenceposts and segment records if necessary when getting more
-    space from the system.  The size at which to autotrim top is
-    cached from mparams in trim_check, except that it is disabled if
-    an autotrim fails.
-
-  Designated victim (dv)
-    This is the preferred chunk for servicing small requests that
-    don't have exact fits.  It is normally the chunk split off most
-    recently to service another small request.  Its size is cached in
-    dvsize. The link fields of this chunk are not maintained since it
-    is not kept in a bin.
-
-  SmallBins
-    An array of bin headers for free chunks.  These bins hold chunks
-    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
-    chunks of all the same size, spaced 8 bytes apart.  To simplify
-    use in double-linked lists, each bin header acts as a malloc_chunk
-    pointing to the real first node, if it exists (else pointing to
-    itself).  This avoids special-casing for headers.  But to avoid
-    waste, we allocate only the fd/bk pointers of bins, and then use
-    repositioning tricks to treat these as the fields of a chunk.
-
-  TreeBins
-    Treebins are pointers to the roots of trees holding a range of
-    sizes. There are 2 equally spaced treebins for each power of two
-    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
-    larger.
-
-  Bin maps
-    There is one bit map for small bins ("smallmap") and one for
-    treebins ("treemap).  Each bin sets its bit when non-empty, and
-    clears the bit when empty.  Bit operations are then used to avoid
-    bin-by-bin searching -- nearly all "search" is done without ever
-    looking at bins that won't be selected.  The bit maps
-    conservatively use 32 bits per map word, even if on 64bit system.
-    For a good description of some of the bit-based techniques used
-    here, see Henry S. Warren Jr's book "Hacker's Delight" (and
-    supplement at http://hackersdelight.org/). Many of these are
-    intended to reduce the branchiness of paths through malloc etc, as
-    well as to reduce the number of memory locations read or written.
-
-  Segments
-    A list of segments headed by an embedded malloc_segment record
-    representing the initial space.
-
-  Address check support
-    The least_addr field is the least address ever obtained from
-    MORECORE or MMAP. Attempted frees and reallocs of any address less
-    than this are trapped (unless INSECURE is defined).
-
-  Magic tag
-    A cross-check field that should always hold same value as mparams.magic.
-
-  Max allowed footprint
-    The maximum allowed bytes to allocate from system (zero means no limit)
-
-  Flags
-    Bits recording whether to use MMAP, locks, or contiguous MORECORE
-
-  Statistics
-    Each space keeps track of current and maximum system memory
-    obtained via MORECORE or MMAP.
-
-  Trim support
-    Fields holding the amount of unused topmost memory that should trigger
-    trimming, and a counter to force periodic scanning to release unused
-    non-topmost segments.
-
-  Locking
-    If USE_LOCKS is defined, the "mutex" lock is acquired and released
-    around every public call using this mspace.
-
-  Extension support
-    A void* pointer and a size_t field that can be used to help implement
-    extensions to this malloc.
-*/
-
-/* Bin types, widths and sizes */
-#define NSMALLBINS        (32U)
-#define NTREEBINS         (32U)
-#define SMALLBIN_SHIFT    (3U)
-#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)
-#define TREEBIN_SHIFT     (8U)
-#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)
-#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)
-#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
-
-struct malloc_state {
-  binmap_t   smallmap;
-  binmap_t   treemap;
-  size_t     dvsize;
-  size_t     topsize;
-  char*      least_addr;
-  mchunkptr  dv;
-  mchunkptr  top;
-  size_t     trim_check;
-  size_t     release_checks;
-  size_t     magic;
-  mchunkptr  smallbins[(NSMALLBINS+1)*2];
-  tbinptr    treebins[NTREEBINS];
-  size_t     footprint;
-  size_t     max_footprint;
-  size_t     footprint_limit; /* zero means no limit */
-  flag_t     mflags;
-#if USE_LOCKS
-  MLOCK_T    mutex;     /* locate lock among fields that rarely change */
-#endif /* USE_LOCKS */
-  msegment   seg;
-  void*      extp;      /* Unused but available for extensions */
-  size_t     exts;
-};
-
-typedef struct malloc_state*    mstate;
-
-/* ------------- Global malloc_state and malloc_params ------------------- */
-
-/*
-  malloc_params holds global properties, including those that can be
-  dynamically set using mallopt. There is a single instance, mparams,
-  initialized in init_mparams. Note that the non-zeroness of "magic"
-  also serves as an initialization flag.
-*/
-
-struct malloc_params {
-  size_t magic;
-  size_t page_size;
-  size_t granularity;
-  size_t mmap_threshold;
-  size_t trim_threshold;
-  flag_t default_mflags;
-};
-
-static struct malloc_params mparams;
-
-/* Ensure mparams initialized */
-#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
-
-#if !ONLY_MSPACES
-
-/* The global malloc_state used for all non-"mspace" calls */
-static struct malloc_state _gm_;
-#define gm                 (&_gm_)
-#define is_global(M)       ((M) == &_gm_)
-
-#endif /* !ONLY_MSPACES */
-
-#define is_initialized(M)  ((M)->top != 0)
-
-/* -------------------------- system alloc setup ------------------------- */
-
-/* Operations on mflags */
-
-#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)
-#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)
-#if USE_LOCKS
-#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)
-#else
-#define disable_lock(M)
-#endif
-
-#define use_mmap(M)           ((M)->mflags &   USE_MMAP_BIT)
-#define enable_mmap(M)        ((M)->mflags |=  USE_MMAP_BIT)
-#if HAVE_MMAP
-#define disable_mmap(M)       ((M)->mflags &= ~USE_MMAP_BIT)
-#else
-#define disable_mmap(M)
-#endif
-
-#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)
-#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)
-
-#define set_lock(M,L)\
- ((M)->mflags = (L)?\
-  ((M)->mflags | USE_LOCK_BIT) :\
-  ((M)->mflags & ~USE_LOCK_BIT))
-
-/* page-align a size */
-#define page_align(S)\
- (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
-
-/* granularity-align a size */
-#define granularity_align(S)\
-  (((S) + (mparams.granularity - SIZE_T_ONE))\
-   & ~(mparams.granularity - SIZE_T_ONE))
-
-
-/* For mmap, use granularity alignment on windows, else page-align */
-#ifdef WIN32
-#define mmap_align(S) granularity_align(S)
-#else
-#define mmap_align(S) page_align(S)
-#endif
-
-/* For sys_alloc, enough padding to ensure can malloc request on success */
-#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
-
-#define is_page_aligned(S)\
-   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
-#define is_granularity_aligned(S)\
-   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
-
-/*  True if segment S holds address A */
-#define segment_holds(S, A)\
-  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
-
-/* Return segment holding given address */
-static msegmentptr segment_holding(mstate m, char* addr) {
-  msegmentptr sp = &m->seg;
-  for (;;) {
-    if (addr >= sp->base && addr < sp->base + sp->size)
-      return sp;
-    if ((sp = sp->next) == 0)
-      return 0;
-  }
-}
-
-/* Return true if segment contains a segment link */
-static int has_segment_link(mstate m, msegmentptr ss) {
-  msegmentptr sp = &m->seg;
-  for (;;) {
-    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
-      return 1;
-    if ((sp = sp->next) == 0)
-      return 0;
-  }
-}
-
-#ifndef MORECORE_CANNOT_TRIM
-#define should_trim(M,s)  ((s) > (M)->trim_check)
-#else  /* MORECORE_CANNOT_TRIM */
-#define should_trim(M,s)  (0)
-#endif /* MORECORE_CANNOT_TRIM */
-
-/*
-  TOP_FOOT_SIZE is padding at the end of a segment, including space
-  that may be needed to place segment records and fenceposts when new
-  noncontiguous segments are added.
-*/
-#define TOP_FOOT_SIZE\
-  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
-
-
-/* -------------------------------  Hooks -------------------------------- */
-
-/*
-  PREACTION should be defined to return 0 on success, and nonzero on
-  failure. If you are not using locking, you can redefine these to do
-  anything you like.
-*/
-
-#if USE_LOCKS
-#define PREACTION(M)  ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
-#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
-#else /* USE_LOCKS */
-
-#ifndef PREACTION
-#define PREACTION(M) (0)
-#endif  /* PREACTION */
-
-#ifndef POSTACTION
-#define POSTACTION(M)
-#endif  /* POSTACTION */
-
-#endif /* USE_LOCKS */
-
-/*
-  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
-  USAGE_ERROR_ACTION is triggered on detected bad frees and
-  reallocs. The argument p is an address that might have triggered the
-  fault. It is ignored by the two predefined actions, but might be
-  useful in custom actions that try to help diagnose errors.
-*/
-
-#if PROCEED_ON_ERROR
-
-/* A count of the number of corruption errors causing resets */
-int malloc_corruption_error_count;
-
-/* default corruption action */
-static void reset_on_error(mstate m);
-
-#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)
-#define USAGE_ERROR_ACTION(m, p)
-
-#else /* PROCEED_ON_ERROR */
-
-#ifndef CORRUPTION_ERROR_ACTION
-#define CORRUPTION_ERROR_ACTION(m) ABORT
-#endif /* CORRUPTION_ERROR_ACTION */
-
-#ifndef USAGE_ERROR_ACTION
-#define USAGE_ERROR_ACTION(m,p) ABORT
-#endif /* USAGE_ERROR_ACTION */
-
-#endif /* PROCEED_ON_ERROR */
-
-
-/* -------------------------- Debugging setup ---------------------------- */
-
-#if ! DEBUG
-
-#define check_free_chunk(M,P)
-#define check_inuse_chunk(M,P)
-#define check_malloced_chunk(M,P,N)
-#define check_mmapped_chunk(M,P)
-#define check_malloc_state(M)
-#define check_top_chunk(M,P)
-
-#else /* DEBUG */
-#define check_free_chunk(M,P)       do_check_free_chunk(M,P)
-#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)
-#define check_top_chunk(M,P)        do_check_top_chunk(M,P)
-#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
-#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)
-#define check_malloc_state(M)       do_check_malloc_state(M)
-
-static void   do_check_any_chunk(mstate m, mchunkptr p);
-static void   do_check_top_chunk(mstate m, mchunkptr p);
-static void   do_check_mmapped_chunk(mstate m, mchunkptr p);
-static void   do_check_inuse_chunk(mstate m, mchunkptr p);
-static void   do_check_free_chunk(mstate m, mchunkptr p);
-static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);
-static void   do_check_tree(mstate m, tchunkptr t);
-static void   do_check_treebin(mstate m, bindex_t i);
-static void   do_check_smallbin(mstate m, bindex_t i);
-static void   do_check_malloc_state(mstate m);
-static int    bin_find(mstate m, mchunkptr x);
-static size_t traverse_and_check(mstate m);
-#endif /* DEBUG */
-
-/* ---------------------------- Indexing Bins ---------------------------- */
-
-#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
-#define small_index(s)      (bindex_t)((s)  >> SMALLBIN_SHIFT)
-#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)
-#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))
-
-/* addressing by index. See above about smallbin repositioning */
-#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
-#define treebin_at(M,i)     (&((M)->treebins[i]))
-
-/* assign tree index for size S to variable I. Use x86 asm if possible  */
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define compute_tree_index(S, I)\
-{\
-  unsigned int X = S >> TREEBIN_SHIFT;\
-  if (X == 0)\
-    I = 0;\
-  else if (X > 0xFFFF)\
-    I = NTREEBINS-1;\
-  else {\
-    unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \
-    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
-  }\
-}
-
-#elif defined (__INTEL_COMPILER)
-#define compute_tree_index(S, I)\
-{\
-  size_t X = S >> TREEBIN_SHIFT;\
-  if (X == 0)\
-    I = 0;\
-  else if (X > 0xFFFF)\
-    I = NTREEBINS-1;\
-  else {\
-    unsigned int K = _bit_scan_reverse (X); \
-    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
-  }\
-}
-
-#elif defined(_MSC_VER) && _MSC_VER>=1300
-#define compute_tree_index(S, I)\
-{\
-  size_t X = S >> TREEBIN_SHIFT;\
-  if (X == 0)\
-    I = 0;\
-  else if (X > 0xFFFF)\
-    I = NTREEBINS-1;\
-  else {\
-    unsigned int K;\
-    _BitScanReverse((DWORD *) &K, (DWORD) X);\
-    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
-  }\
-}
-
-#else /* GNUC */
-#define compute_tree_index(S, I)\
-{\
-  size_t X = S >> TREEBIN_SHIFT;\
-  if (X == 0)\
-    I = 0;\
-  else if (X > 0xFFFF)\
-    I = NTREEBINS-1;\
-  else {\
-    unsigned int Y = (unsigned int)X;\
-    unsigned int N = ((Y - 0x100) >> 16) & 8;\
-    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
-    N += K;\
-    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
-    K = 14 - N + ((Y <<= K) >> 15);\
-    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
-  }\
-}
-#endif /* GNUC */
-
-/* Bit representing maximum resolved size in a treebin at i */
-#define bit_for_tree_index(i) \
-   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
-
-/* Shift placing maximum resolved bit in a treebin at i as sign bit */
-#define leftshift_for_tree_index(i) \
-   ((i == NTREEBINS-1)? 0 : \
-    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
-
-/* The size of the smallest chunk held in bin with index i */
-#define minsize_for_tree_index(i) \
-   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \
-   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
-
-
-/* ------------------------ Operations on bin maps ----------------------- */
-
-/* bit corresponding to given index */
-#define idx2bit(i)              ((binmap_t)(1) << (i))
-
-/* Mark/Clear bits with given index */
-#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))
-#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))
-#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))
-
-#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))
-#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))
-#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))
-
-/* isolate the least set bit of a bitmap */
-#define least_bit(x)         ((x) & -(x))
-
-/* mask with all bits to left of least bit of x on */
-#define left_bits(x)         ((x<<1) | -(x<<1))
-
-/* mask with all bits to left of or equal to least bit of x on */
-#define same_or_left_bits(x) ((x) | -(x))
-
-/* index corresponding to given bit. Use x86 asm if possible */
-
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define compute_bit2idx(X, I)\
-{\
-  unsigned int J;\
-  J = __builtin_ctz(X); \
-  I = (bindex_t)J;\
-}
-
-#elif defined (__INTEL_COMPILER)
-#define compute_bit2idx(X, I)\
-{\
-  unsigned int J;\
-  J = _bit_scan_forward (X); \
-  I = (bindex_t)J;\
-}
-
-#elif defined(_MSC_VER) && _MSC_VER>=1300
-#define compute_bit2idx(X, I)\
-{\
-  unsigned int J;\
-  _BitScanForward((DWORD *) &J, X);\
-  I = (bindex_t)J;\
-}
-
-#elif USE_BUILTIN_FFS
-#define compute_bit2idx(X, I) I = ffs(X)-1
-
-#else
-#define compute_bit2idx(X, I)\
-{\
-  unsigned int Y = X - 1;\
-  unsigned int K = Y >> (16-4) & 16;\
-  unsigned int N = K;        Y >>= K;\
-  N += K = Y >> (8-3) &  8;  Y >>= K;\
-  N += K = Y >> (4-2) &  4;  Y >>= K;\
-  N += K = Y >> (2-1) &  2;  Y >>= K;\
-  N += K = Y >> (1-0) &  1;  Y >>= K;\
-  I = (bindex_t)(N + Y);\
-}
-#endif /* GNUC */
-
-
-/* ----------------------- Runtime Check Support ------------------------- */
-
-/*
-  For security, the main invariant is that malloc/free/etc never
-  writes to a static address other than malloc_state, unless static
-  malloc_state itself has been corrupted, which cannot occur via
-  malloc (because of these checks). In essence this means that we
-  believe all pointers, sizes, maps etc held in malloc_state, but
-  check all of those linked or offsetted from other embedded data
-  structures.  These checks are interspersed with main code in a way
-  that tends to minimize their run-time cost.
-
-  When FOOTERS is defined, in addition to range checking, we also
-  verify footer fields of inuse chunks, which can be used guarantee
-  that the mstate controlling malloc/free is intact.  This is a
-  streamlined version of the approach described by William Robertson
-  et al in "Run-time Detection of Heap-based Overflows" LISA'03
-  http://www.usenix.org/events/lisa03/tech/robertson.html The footer
-  of an inuse chunk holds the xor of its mstate and a random seed,
-  that is checked upon calls to free() and realloc().  This is
-  (probabalistically) unguessable from outside the program, but can be
-  computed by any code successfully malloc'ing any chunk, so does not
-  itself provide protection against code that has already broken
-  security through some other means.  Unlike Robertson et al, we
-  always dynamically check addresses of all offset chunks (previous,
-  next, etc). This turns out to be cheaper than relying on hashes.
-*/
-
-#if !INSECURE
-/* Check if address a is at least as high as any from MORECORE or MMAP */
-#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
-/* Check if address of next chunk n is higher than base chunk p */
-#define ok_next(p, n)    ((char*)(p) < (char*)(n))
-/* Check if p has inuse status */
-#define ok_inuse(p)     is_inuse(p)
-/* Check if p has its pinuse bit on */
-#define ok_pinuse(p)     pinuse(p)
-
-#else /* !INSECURE */
-#define ok_address(M, a) (1)
-#define ok_next(b, n)    (1)
-#define ok_inuse(p)      (1)
-#define ok_pinuse(p)     (1)
-#endif /* !INSECURE */
-
-#if (FOOTERS && !INSECURE)
-/* Check if (alleged) mstate m has expected magic field */
-#define ok_magic(M)      ((M)->magic == mparams.magic)
-#else  /* (FOOTERS && !INSECURE) */
-#define ok_magic(M)      (1)
-#endif /* (FOOTERS && !INSECURE) */
-
-/* In gcc, use __builtin_expect to minimize impact of checks */
-#if !INSECURE
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define RTCHECK(e)  __builtin_expect(e, 1)
-#else /* GNUC */
-#define RTCHECK(e)  (e)
-#endif /* GNUC */
-#else /* !INSECURE */
-#define RTCHECK(e)  (1)
-#endif /* !INSECURE */
-
-/* macros to set up inuse chunks with or without footers */
-
-#if !FOOTERS
-
-#define mark_inuse_foot(M,p,s)
-
-/* Macros for setting head/foot of non-mmapped chunks */
-
-/* Set cinuse bit and pinuse bit of next chunk */
-#define set_inuse(M,p,s)\
-  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
-  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
-#define set_inuse_and_pinuse(M,p,s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
-  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set size, cinuse and pinuse bit of this chunk */
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
-
-#else /* FOOTERS */
-
-/* Set foot of inuse chunk to be xor of mstate and seed */
-#define mark_inuse_foot(M,p,s)\
-  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
-
-#define get_mstate_for(p)\
-  ((mstate)(((mchunkptr)((char*)(p) +\
-    (chunksize(p))))->prev_foot ^ mparams.magic))
-
-#define set_inuse(M,p,s)\
-  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
-  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
-  mark_inuse_foot(M,p,s))
-
-#define set_inuse_and_pinuse(M,p,s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
-  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
- mark_inuse_foot(M,p,s))
-
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
-  mark_inuse_foot(M, p, s))
-
-#endif /* !FOOTERS */
-
-/* ---------------------------- setting mparams -------------------------- */
-
-#if LOCK_AT_FORK
-static void pre_fork(void)         { ACQUIRE_LOCK(&(gm)->mutex); }
-static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); }
-static void post_fork_child(void)  { INITIAL_LOCK(&(gm)->mutex); }
-#endif /* LOCK_AT_FORK */
-
-/* Initialize mparams */
-static int init_mparams(void) {
-#ifdef NEED_GLOBAL_LOCK_INIT
-  if (malloc_global_mutex_status <= 0)
-    init_malloc_global_mutex();
-#endif
-
-  ACQUIRE_MALLOC_GLOBAL_LOCK();
-  if (mparams.magic == 0) {
-    size_t magic;
-    size_t psize;
-    size_t gsize;
-
-#ifndef WIN32
-    psize = malloc_getpagesize;
-    gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
-#else /* WIN32 */
-    {
-      SYSTEM_INFO system_info;
-      GetSystemInfo(&system_info);
-      psize = system_info.dwPageSize;
-      gsize = ((DEFAULT_GRANULARITY != 0)?
-               DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
-    }
-#endif /* WIN32 */
-
-    /* Sanity-check configuration:
-       size_t must be unsigned and as wide as pointer type.
-       ints must be at least 4 bytes.
-       alignment must be at least 8.
-       Alignment, min chunk size, and page size must all be powers of 2.
-    */
-    if ((sizeof(size_t) != sizeof(char*)) ||
-        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
-        (sizeof(int) < 4)  ||
-        (MALLOC_ALIGNMENT < (size_t)8U) ||
-        ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
-        ((MCHUNK_SIZE      & (MCHUNK_SIZE-SIZE_T_ONE))      != 0) ||
-        ((gsize            & (gsize-SIZE_T_ONE))            != 0) ||
-        ((psize            & (psize-SIZE_T_ONE))            != 0))
-      ABORT;
-    mparams.granularity = gsize;
-    mparams.page_size = psize;
-    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
-    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
-#if MORECORE_CONTIGUOUS
-    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
-#else  /* MORECORE_CONTIGUOUS */
-    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
-#endif /* MORECORE_CONTIGUOUS */
-
-#if !ONLY_MSPACES
-    /* Set up lock for main malloc area */
-    gm->mflags = mparams.default_mflags;
-    (void)INITIAL_LOCK(&gm->mutex);
-#endif
-#if LOCK_AT_FORK
-    pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);
-#endif
-
-    {
-#if USE_DEV_RANDOM
-      int fd;
-      unsigned char buf[sizeof(size_t)];
-      /* Try to use /dev/urandom, else fall back on using time */
-      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
-          read(fd, buf, sizeof(buf)) == sizeof(buf)) {
-        magic = *((size_t *) buf);
-        close(fd);
-      }
-      else
-#endif /* USE_DEV_RANDOM */
-#ifdef WIN32
-      magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
-#elif defined(LACKS_TIME_H)
-      magic = (size_t)&magic ^ (size_t)0x55555555U;
-#else
-      magic = (size_t)(time(0) ^ (size_t)0x55555555U);
-#endif
-      magic |= (size_t)8U;    /* ensure nonzero */
-      magic &= ~(size_t)7U;   /* improve chances of fault for bad values */
-      /* Until memory modes commonly available, use volatile-write */
-      (*(volatile size_t *)(&(mparams.magic))) = magic;
-    }
-  }
-
-  RELEASE_MALLOC_GLOBAL_LOCK();
-  return 1;
-}
-
-/* support for mallopt */
-static int change_mparam(int param_number, int value) {
-  size_t val;
-  ensure_initialization();
-  val = (value == -1)? MAX_SIZE_T : (size_t)value;
-  switch(param_number) {
-  case M_TRIM_THRESHOLD:
-    mparams.trim_threshold = val;
-    return 1;
-  case M_GRANULARITY:
-    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
-      mparams.granularity = val;
-      return 1;
-    }
-    else
-      return 0;
-  case M_MMAP_THRESHOLD:
-    mparams.mmap_threshold = val;
-    return 1;
-  default:
-    return 0;
-  }
-}
-
-#if DEBUG
-/* ------------------------- Debugging Support --------------------------- */
-
-/* Check properties of any chunk, whether free, inuse, mmapped etc  */
-static void do_check_any_chunk(mstate m, mchunkptr p) {
-  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
-  assert(ok_address(m, p));
-}
-
-/* Check properties of top chunk */
-static void do_check_top_chunk(mstate m, mchunkptr p) {
-  msegmentptr sp = segment_holding(m, (char*)p);
-  size_t  sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
-  assert(sp != 0);
-  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
-  assert(ok_address(m, p));
-  assert(sz == m->topsize);
-  assert(sz > 0);
-  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
-  assert(pinuse(p));
-  assert(!pinuse(chunk_plus_offset(p, sz)));
-}
-
-/* Check properties of (inuse) mmapped chunks */
-static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
-  size_t  sz = chunksize(p);
-  size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);
-  assert(is_mmapped(p));
-  assert(use_mmap(m));
-  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
-  assert(ok_address(m, p));
-  assert(!is_small(sz));
-  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
-  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
-  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
-}
-
-/* Check properties of inuse chunks */
-static void do_check_inuse_chunk(mstate m, mchunkptr p) {
-  do_check_any_chunk(m, p);
-  assert(is_inuse(p));
-  assert(next_pinuse(p));
-  /* If not pinuse and not mmapped, previous chunk has OK offset */
-  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
-  if (is_mmapped(p))
-    do_check_mmapped_chunk(m, p);
-}
-
-/* Check properties of free chunks */
-static void do_check_free_chunk(mstate m, mchunkptr p) {
-  size_t sz = chunksize(p);
-  mchunkptr next = chunk_plus_offset(p, sz);
-  do_check_any_chunk(m, p);
-  assert(!is_inuse(p));
-  assert(!next_pinuse(p));
-  assert (!is_mmapped(p));
-  if (p != m->dv && p != m->top) {
-    if (sz >= MIN_CHUNK_SIZE) {
-      assert((sz & CHUNK_ALIGN_MASK) == 0);
-      assert(is_aligned(chunk2mem(p)));
-      assert(next->prev_foot == sz);
-      assert(pinuse(p));
-      assert (next == m->top || is_inuse(next));
-      assert(p->fd->bk == p);
-      assert(p->bk->fd == p);
-    }
-    else  /* markers are always of size SIZE_T_SIZE */
-      assert(sz == SIZE_T_SIZE);
-  }
-}
-
-/* Check properties of malloced chunks at the point they are malloced */
-static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
-  if (mem != 0) {
-    mchunkptr p = mem2chunk(mem);
-    size_t sz = p->head & ~INUSE_BITS;
-    do_check_inuse_chunk(m, p);
-    assert((sz & CHUNK_ALIGN_MASK) == 0);
-    assert(sz >= MIN_CHUNK_SIZE);
-    assert(sz >= s);
-    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
-    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
-  }
-}
-
-/* Check a tree and its subtrees.  */
-static void do_check_tree(mstate m, tchunkptr t) {
-  tchunkptr head = 0;
-  tchunkptr u = t;
-  bindex_t tindex = t->index;
-  size_t tsize = chunksize(t);
-  bindex_t idx;
-  compute_tree_index(tsize, idx);
-  assert(tindex == idx);
-  assert(tsize >= MIN_LARGE_SIZE);
-  assert(tsize >= minsize_for_tree_index(idx));
-  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
-
-  do { /* traverse through chain of same-sized nodes */
-    do_check_any_chunk(m, ((mchunkptr)u));
-    assert(u->index == tindex);
-    assert(chunksize(u) == tsize);
-    assert(!is_inuse(u));
-    assert(!next_pinuse(u));
-    assert(u->fd->bk == u);
-    assert(u->bk->fd == u);
-    if (u->parent == 0) {
-      assert(u->child[0] == 0);
-      assert(u->child[1] == 0);
-    }
-    else {
-      assert(head == 0); /* only one node on chain has parent */
-      head = u;
-      assert(u->parent != u);
-      assert (u->parent->child[0] == u ||
-              u->parent->child[1] == u ||
-              *((tbinptr*)(u->parent)) == u);
-      if (u->child[0] != 0) {
-        assert(u->child[0]->parent == u);
-        assert(u->child[0] != u);
-        do_check_tree(m, u->child[0]);
-      }
-      if (u->child[1] != 0) {
-        assert(u->child[1]->parent == u);
-        assert(u->child[1] != u);
-        do_check_tree(m, u->child[1]);
-      }
-      if (u->child[0] != 0 && u->child[1] != 0) {
-        assert(chunksize(u->child[0]) < chunksize(u->child[1]));
-      }
-    }
-    u = u->fd;
-  } while (u != t);
-  assert(head != 0);
-}
-
-/*  Check all the chunks in a treebin.  */
-static void do_check_treebin(mstate m, bindex_t i) {
-  tbinptr* tb = treebin_at(m, i);
-  tchunkptr t = *tb;
-  int empty = (m->treemap & (1U << i)) == 0;
-  if (t == 0)
-    assert(empty);
-  if (!empty)
-    do_check_tree(m, t);
-}
-
-/*  Check all the chunks in a smallbin.  */
-static void do_check_smallbin(mstate m, bindex_t i) {
-  sbinptr b = smallbin_at(m, i);
-  mchunkptr p = b->bk;
-  unsigned int empty = (m->smallmap & (1U << i)) == 0;
-  if (p == b)
-    assert(empty);
-  if (!empty) {
-    for (; p != b; p = p->bk) {
-      size_t size = chunksize(p);
-      mchunkptr q;
-      /* each chunk claims to be free */
-      do_check_free_chunk(m, p);
-      /* chunk belongs in bin */
-      assert(small_index(size) == i);
-      assert(p->bk == b || chunksize(p->bk) == chunksize(p));
-      /* chunk is followed by an inuse chunk */
-      q = next_chunk(p);
-      if (q->head != FENCEPOST_HEAD)
-        do_check_inuse_chunk(m, q);
-    }
-  }
-}
-
-/* Find x in a bin. Used in other check functions. */
-static int bin_find(mstate m, mchunkptr x) {
-  size_t size = chunksize(x);
-  if (is_small(size)) {
-    bindex_t sidx = small_index(size);
-    sbinptr b = smallbin_at(m, sidx);
-    if (smallmap_is_marked(m, sidx)) {
-      mchunkptr p = b;
-      do {
-        if (p == x)
-          return 1;
-      } while ((p = p->fd) != b);
-    }
-  }
-  else {
-    bindex_t tidx;
-    compute_tree_index(size, tidx);
-    if (treemap_is_marked(m, tidx)) {
-      tchunkptr t = *treebin_at(m, tidx);
-      size_t sizebits = size << leftshift_for_tree_index(tidx);
-      while (t != 0 && chunksize(t) != size) {
-        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
-        sizebits <<= 1;
-      }
-      if (t != 0) {
-        tchunkptr u = t;
-        do {
-          if (u == (tchunkptr)x)
-            return 1;
-        } while ((u = u->fd) != t);
-      }
-    }
-  }
-  return 0;
-}
-
-/* Traverse each chunk and check it; return total */
-static size_t traverse_and_check(mstate m) {
-  size_t sum = 0;
-  if (is_initialized(m)) {
-    msegmentptr s = &m->seg;
-    sum += m->topsize + TOP_FOOT_SIZE;
-    while (s != 0) {
-      mchunkptr q = align_as_chunk(s->base);
-      mchunkptr lastq = 0;
-      assert(pinuse(q));
-      while (segment_holds(s, q) &&
-             q != m->top && q->head != FENCEPOST_HEAD) {
-        sum += chunksize(q);
-        if (is_inuse(q)) {
-          assert(!bin_find(m, q));
-          do_check_inuse_chunk(m, q);
-        }
-        else {
-          assert(q == m->dv || bin_find(m, q));
-          assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */
-          do_check_free_chunk(m, q);
-        }
-        lastq = q;
-        q = next_chunk(q);
-      }
-      s = s->next;
-    }
-  }
-  return sum;
-}
-
-
-/* Check all properties of malloc_state. */
-static void do_check_malloc_state(mstate m) {
-  bindex_t i;
-  size_t total;
-  /* check bins */
-  for (i = 0; i < NSMALLBINS; ++i)
-    do_check_smallbin(m, i);
-  for (i = 0; i < NTREEBINS; ++i)
-    do_check_treebin(m, i);
-
-  if (m->dvsize != 0) { /* check dv chunk */
-    do_check_any_chunk(m, m->dv);
-    assert(m->dvsize == chunksize(m->dv));
-    assert(m->dvsize >= MIN_CHUNK_SIZE);
-    assert(bin_find(m, m->dv) == 0);
-  }
-
-  if (m->top != 0) {   /* check top chunk */
-    do_check_top_chunk(m, m->top);
-    /*assert(m->topsize == chunksize(m->top)); redundant */
-    assert(m->topsize > 0);
-    assert(bin_find(m, m->top) == 0);
-  }
-
-  total = traverse_and_check(m);
-  assert(total <= m->footprint);
-  assert(m->footprint <= m->max_footprint);
-}
-#endif /* DEBUG */
-
-/* ----------------------------- statistics ------------------------------ */
-
-#if !NO_MALLINFO
-static struct mallinfo internal_mallinfo(mstate m) {
-  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-  ensure_initialization();
-  if (!PREACTION(m)) {
-    check_malloc_state(m);
-    if (is_initialized(m)) {
-      size_t nfree = SIZE_T_ONE; /* top always free */
-      size_t mfree = m->topsize + TOP_FOOT_SIZE;
-      size_t sum = mfree;
-      msegmentptr s = &m->seg;
-      while (s != 0) {
-        mchunkptr q = align_as_chunk(s->base);
-        while (segment_holds(s, q) &&
-               q != m->top && q->head != FENCEPOST_HEAD) {
-          size_t sz = chunksize(q);
-          sum += sz;
-          if (!is_inuse(q)) {
-            mfree += sz;
-            ++nfree;
-          }
-          q = next_chunk(q);
-        }
-        s = s->next;
-      }
-
-      nm.arena    = sum;
-      nm.ordblks  = nfree;
-      nm.hblkhd   = m->footprint - sum;
-      nm.usmblks  = m->max_footprint;
-      nm.uordblks = m->footprint - mfree;
-      nm.fordblks = mfree;
-      nm.keepcost = m->topsize;
-    }
-
-    POSTACTION(m);
-  }
-  return nm;
-}
-#endif /* !NO_MALLINFO */
-
-#if !NO_MALLOC_STATS
-static void internal_malloc_stats(mstate m) {
-  ensure_initialization();
-  if (!PREACTION(m)) {
-    size_t maxfp = 0;
-    size_t fp = 0;
-    size_t used = 0;
-    check_malloc_state(m);
-    if (is_initialized(m)) {
-      msegmentptr s = &m->seg;
-      maxfp = m->max_footprint;
-      fp = m->footprint;
-      used = fp - (m->topsize + TOP_FOOT_SIZE);
-
-      while (s != 0) {
-        mchunkptr q = align_as_chunk(s->base);
-        while (segment_holds(s, q) &&
-               q != m->top && q->head != FENCEPOST_HEAD) {
-          if (!is_inuse(q))
-            used -= chunksize(q);
-          q = next_chunk(q);
-        }
-        s = s->next;
-      }
-    }
-    POSTACTION(m); /* drop lock */
-    fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
-    fprintf(stderr, "system bytes     = %10lu\n", (unsigned long)(fp));
-    fprintf(stderr, "in use bytes     = %10lu\n", (unsigned long)(used));
-  }
-}
-#endif /* NO_MALLOC_STATS */
-
-/* ----------------------- Operations on smallbins ----------------------- */
-
-/*
-  Various forms of linking and unlinking are defined as macros.  Even
-  the ones for trees, which are very long but have very short typical
-  paths.  This is ugly but reduces reliance on inlining support of
-  compilers.
-*/
-
-/* Link a free chunk into a smallbin  */
-#define insert_small_chunk(M, P, S) {\
-  bindex_t I  = small_index(S);\
-  mchunkptr B = smallbin_at(M, I);\
-  mchunkptr F = B;\
-  assert(S >= MIN_CHUNK_SIZE);\
-  if (!smallmap_is_marked(M, I))\
-    mark_smallmap(M, I);\
-  else if (RTCHECK(ok_address(M, B->fd)))\
-    F = B->fd;\
-  else {\
-    CORRUPTION_ERROR_ACTION(M);\
-  }\
-  B->fd = P;\
-  F->bk = P;\
-  P->fd = F;\
-  P->bk = B;\
-}
-
-/* Unlink a chunk from a smallbin  */
-#define unlink_small_chunk(M, P, S) {\
-  mchunkptr F = P->fd;\
-  mchunkptr B = P->bk;\
-  bindex_t I = small_index(S);\
-  assert(P != B);\
-  assert(P != F);\
-  assert(chunksize(P) == small_index2size(I));\
-  if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \
-    if (B == F) {\
-      clear_smallmap(M, I);\
-    }\
-    else if (RTCHECK(B == smallbin_at(M,I) ||\
-                     (ok_address(M, B) && B->fd == P))) {\
-      F->bk = B;\
-      B->fd = F;\
-    }\
-    else {\
-      CORRUPTION_ERROR_ACTION(M);\
-    }\
-  }\
-  else {\
-    CORRUPTION_ERROR_ACTION(M);\
-  }\
-}
-
-/* Unlink the first chunk from a smallbin */
-#define unlink_first_small_chunk(M, B, P, I) {\
-  mchunkptr F = P->fd;\
-  assert(P != B);\
-  assert(P != F);\
-  assert(chunksize(P) == small_index2size(I));\
-  if (B == F) {\
-    clear_smallmap(M, I);\
-  }\
-  else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\
-    F->bk = B;\
-    B->fd = F;\
-  }\
-  else {\
-    CORRUPTION_ERROR_ACTION(M);\
-  }\
-}
-
-/* Replace dv node, binning the old one */
-/* Used only when dvsize known to be small */
-#define replace_dv(M, P, S) {\
-  size_t DVS = M->dvsize;\
-  assert(is_small(DVS));\
-  if (DVS != 0) {\
-    mchunkptr DV = M->dv;\
-    insert_small_chunk(M, DV, DVS);\
-  }\
-  M->dvsize = S;\
-  M->dv = P;\
-}
-
-/* ------------------------- Operations on trees ------------------------- */
-
-/* Insert chunk into tree */
-#define insert_large_chunk(M, X, S) {\
-  tbinptr* H;\
-  bindex_t I;\
-  compute_tree_index(S, I);\
-  H = treebin_at(M, I);\
-  X->index = I;\
-  X->child[0] = X->child[1] = 0;\
-  if (!treemap_is_marked(M, I)) {\
-    mark_treemap(M, I);\
-    *H = X;\
-    X->parent = (tchunkptr)H;\
-    X->fd = X->bk = X;\
-  }\
-  else {\
-    tchunkptr T = *H;\
-    size_t K = S << leftshift_for_tree_index(I);\
-    for (;;) {\
-      if (chunksize(T) != S) {\
-        tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
-        K <<= 1;\
-        if (*C != 0)\
-          T = *C;\
-        else if (RTCHECK(ok_address(M, C))) {\
-          *C = X;\
-          X->parent = T;\
-          X->fd = X->bk = X;\
-          break;\
-        }\
-        else {\
-          CORRUPTION_ERROR_ACTION(M);\
-          break;\
-        }\
-      }\
-      else {\
-        tchunkptr F = T->fd;\
-        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
-          T->fd = F->bk = X;\
-          X->fd = F;\
-          X->bk = T;\
-          X->parent = 0;\
-          break;\
-        }\
-        else {\
-          CORRUPTION_ERROR_ACTION(M);\
-          break;\
-        }\
-      }\
-    }\
-  }\
-}
-
-/*
-  Unlink steps:
-
-  1. If x is a chained node, unlink it from its same-sized fd/bk links
-     and choose its bk node as its replacement.
-  2. If x was the last node of its size, but not a leaf node, it must
-     be replaced with a leaf node (not merely one with an open left or
-     right), to make sure that lefts and rights of descendents
-     correspond properly to bit masks.  We use the rightmost descendent
-     of x.  We could use any other leaf, but this is easy to locate and
-     tends to counteract removal of leftmosts elsewhere, and so keeps
-     paths shorter than minimally guaranteed.  This doesn't loop much
-     because on average a node in a tree is near the bottom.
-  3. If x is the base of a chain (i.e., has parent links) relink
-     x's parent and children to x's replacement (or null if none).
-*/
-
-#define unlink_large_chunk(M, X) {\
-  tchunkptr XP = X->parent;\
-  tchunkptr R;\
-  if (X->bk != X) {\
-    tchunkptr F = X->fd;\
-    R = X->bk;\
-    if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\
-      F->bk = R;\
-      R->fd = F;\
-    }\
-    else {\
-      CORRUPTION_ERROR_ACTION(M);\
-    }\
-  }\
-  else {\
-    tchunkptr* RP;\
-    if (((R = *(RP = &(X->child[1]))) != 0) ||\
-        ((R = *(RP = &(X->child[0]))) != 0)) {\
-      tchunkptr* CP;\
-      while ((*(CP = &(R->child[1])) != 0) ||\
-             (*(CP = &(R->child[0])) != 0)) {\
-        R = *(RP = CP);\
-      }\
-      if (RTCHECK(ok_address(M, RP)))\
-        *RP = 0;\
-      else {\
-        CORRUPTION_ERROR_ACTION(M);\
-      }\
-    }\
-  }\
-  if (XP != 0) {\
-    tbinptr* H = treebin_at(M, X->index);\
-    if (X == *H) {\
-      if ((*H = R) == 0) \
-        clear_treemap(M, X->index);\
-    }\
-    else if (RTCHECK(ok_address(M, XP))) {\
-      if (XP->child[0] == X) \
-        XP->child[0] = R;\
-      else \
-        XP->child[1] = R;\
-    }\
-    else\
-      CORRUPTION_ERROR_ACTION(M);\
-    if (R != 0) {\
-      if (RTCHECK(ok_address(M, R))) {\
-        tchunkptr C0, C1;\
-        R->parent = XP;\
-        if ((C0 = X->child[0]) != 0) {\
-          if (RTCHECK(ok_address(M, C0))) {\
-            R->child[0] = C0;\
-            C0->parent = R;\
-          }\
-          else\
-            CORRUPTION_ERROR_ACTION(M);\
-        }\
-        if ((C1 = X->child[1]) != 0) {\
-          if (RTCHECK(ok_address(M, C1))) {\
-            R->child[1] = C1;\
-            C1->parent = R;\
-          }\
-          else\
-            CORRUPTION_ERROR_ACTION(M);\
-        }\
-      }\
-      else\
-        CORRUPTION_ERROR_ACTION(M);\
-    }\
-  }\
-}
-
-/* Relays to large vs small bin operations */
-
-#define insert_chunk(M, P, S)\
-  if (is_small(S)) insert_small_chunk(M, P, S)\
-  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
-
-#define unlink_chunk(M, P, S)\
-  if (is_small(S)) unlink_small_chunk(M, P, S)\
-  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
-
-
-/* Relays to internal calls to malloc/free from realloc, memalign etc */
-
-#if ONLY_MSPACES
-#define internal_malloc(m, b) mspace_malloc(m, b)
-#define internal_free(m, mem) mspace_free(m,mem);
-#else /* ONLY_MSPACES */
-#if MSPACES
-#define internal_malloc(m, b)\
-  ((m == gm)? dlmalloc(b) : mspace_malloc(m, b))
-#define internal_free(m, mem)\
-   if (m == gm) dlfree(mem); else mspace_free(m,mem);
-#else /* MSPACES */
-#define internal_malloc(m, b) dlmalloc(b)
-#define internal_free(m, mem) dlfree(mem)
-#endif /* MSPACES */
-#endif /* ONLY_MSPACES */
-
-/* -----------------------  Direct-mmapping chunks ----------------------- */
-
-/*
-  Directly mmapped chunks are set up with an offset to the start of
-  the mmapped region stored in the prev_foot field of the chunk. This
-  allows reconstruction of the required argument to MUNMAP when freed,
-  and also allows adjustment of the returned chunk to meet alignment
-  requirements (especially in memalign).
-*/
-
-/* Malloc using mmap */
-static void* mmap_alloc(mstate m, size_t nb) {
-  size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
-  if (m->footprint_limit != 0) {
-    size_t fp = m->footprint + mmsize;
-    if (fp <= m->footprint || fp > m->footprint_limit)
-      return 0;
-  }
-  if (mmsize > nb) {     /* Check for wrap around 0 */
-    char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
-    if (mm != CMFAIL) {
-      size_t offset = align_offset(chunk2mem(mm));
-      size_t psize = mmsize - offset - MMAP_FOOT_PAD;
-      mchunkptr p = (mchunkptr)(mm + offset);
-      p->prev_foot = offset;
-      p->head = psize;
-      mark_inuse_foot(m, p, psize);
-      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
-      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
-
-      if (m->least_addr == 0 || mm < m->least_addr)
-        m->least_addr = mm;
-      if ((m->footprint += mmsize) > m->max_footprint)
-        m->max_footprint = m->footprint;
-      assert(is_aligned(chunk2mem(p)));
-      check_mmapped_chunk(m, p);
-      return chunk2mem(p);
-    }
-  }
-  return 0;
-}
-
-/* Realloc using mmap */
-static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {
-  size_t oldsize = chunksize(oldp);
-  (void)flags; /* placate people compiling -Wunused */
-  if (is_small(nb)) /* Can't shrink mmap regions below small size */
-    return 0;
-  /* Keep old chunk if big enough but not too big */
-  if (oldsize >= nb + SIZE_T_SIZE &&
-      (oldsize - nb) <= (mparams.granularity << 1))
-    return oldp;
-  else {
-    size_t offset = oldp->prev_foot;
-    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
-    size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
-    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
-                                  oldmmsize, newmmsize, flags);
-    if (cp != CMFAIL) {
-      mchunkptr newp = (mchunkptr)(cp + offset);
-      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
-      newp->head = psize;
-      mark_inuse_foot(m, newp, psize);
-      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
-      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
-
-      if (cp < m->least_addr)
-        m->least_addr = cp;
-      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
-        m->max_footprint = m->footprint;
-      check_mmapped_chunk(m, newp);
-      return newp;
-    }
-  }
-  return 0;
-}
-
-
-/* -------------------------- mspace management -------------------------- */
-
-/* Initialize top chunk and its size */
-static void init_top(mstate m, mchunkptr p, size_t psize) {
-  /* Ensure alignment */
-  size_t offset = align_offset(chunk2mem(p));
-  p = (mchunkptr)((char*)p + offset);
-  psize -= offset;
-
-  m->top = p;
-  m->topsize = psize;
-  p->head = psize | PINUSE_BIT;
-  /* set size of fake trailing chunk holding overhead space only once */
-  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
-  m->trim_check = mparams.trim_threshold; /* reset on each update */
-}
-
-/* Initialize bins for a new mstate that is otherwise zeroed out */
-static void init_bins(mstate m) {
-  /* Establish circular links for smallbins */
-  bindex_t i;
-  for (i = 0; i < NSMALLBINS; ++i) {
-    sbinptr bin = smallbin_at(m,i);
-    bin->fd = bin->bk = bin;
-  }
-}
-
-#if PROCEED_ON_ERROR
-
-/* default corruption action */
-static void reset_on_error(mstate m) {
-  int i;
-  ++malloc_corruption_error_count;
-  /* Reinitialize fields to forget about all memory */
-  m->smallmap = m->treemap = 0;
-  m->dvsize = m->topsize = 0;
-  m->seg.base = 0;
-  m->seg.size = 0;
-  m->seg.next = 0;
-  m->top = m->dv = 0;
-  for (i = 0; i < NTREEBINS; ++i)
-    *treebin_at(m, i) = 0;
-  init_bins(m);
-}
-#endif /* PROCEED_ON_ERROR */
-
-/* Allocate chunk and prepend remainder with chunk in successor base. */
-static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
-                           size_t nb) {
-  mchunkptr p = align_as_chunk(newbase);
-  mchunkptr oldfirst = align_as_chunk(oldbase);
-  size_t psize = (char*)oldfirst - (char*)p;
-  mchunkptr q = chunk_plus_offset(p, nb);
-  size_t qsize = psize - nb;
-  set_size_and_pinuse_of_inuse_chunk(m, p, nb);
-
-  assert((char*)oldfirst > (char*)q);
-  assert(pinuse(oldfirst));
-  assert(qsize >= MIN_CHUNK_SIZE);
-
-  /* consolidate remainder with first chunk of old base */
-  if (oldfirst == m->top) {
-    size_t tsize = m->topsize += qsize;
-    m->top = q;
-    q->head = tsize | PINUSE_BIT;
-    check_top_chunk(m, q);
-  }
-  else if (oldfirst == m->dv) {
-    size_t dsize = m->dvsize += qsize;
-    m->dv = q;
-    set_size_and_pinuse_of_free_chunk(q, dsize);
-  }
-  else {
-    if (!is_inuse(oldfirst)) {
-      size_t nsize = chunksize(oldfirst);
-      unlink_chunk(m, oldfirst, nsize);
-      oldfirst = chunk_plus_offset(oldfirst, nsize);
-      qsize += nsize;
-    }
-    set_free_with_pinuse(q, qsize, oldfirst);
-    insert_chunk(m, q, qsize);
-    check_free_chunk(m, q);
-  }
-
-  check_malloced_chunk(m, chunk2mem(p), nb);
-  return chunk2mem(p);
-}
-
-/* Add a segment to hold a new noncontiguous region */
-static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
-  /* Determine locations and sizes of segment, fenceposts, old top */
-  char* old_top = (char*)m->top;
-  msegmentptr oldsp = segment_holding(m, old_top);
-  char* old_end = oldsp->base + oldsp->size;
-  size_t ssize = pad_request(sizeof(struct malloc_segment));
-  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
-  size_t offset = align_offset(chunk2mem(rawsp));
-  char* asp = rawsp + offset;
-  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
-  mchunkptr sp = (mchunkptr)csp;
-  msegmentptr ss = (msegmentptr)(chunk2mem(sp));
-  mchunkptr tnext = chunk_plus_offset(sp, ssize);
-  mchunkptr p = tnext;
-  int nfences = 0;
-
-  /* reset top to new space */
-  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
-
-  /* Set up segment record */
-  assert(is_aligned(ss));
-  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
-  *ss = m->seg; /* Push current record */
-  m->seg.base = tbase;
-  m->seg.size = tsize;
-  m->seg.sflags = mmapped;
-  m->seg.next = ss;
-
-  /* Insert trailing fenceposts */
-  for (;;) {
-    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
-    p->head = FENCEPOST_HEAD;
-    ++nfences;
-    if ((char*)(&(nextp->head)) < old_end)
-      p = nextp;
-    else
-      break;
-  }
-  assert(nfences >= 2);
-
-  /* Insert the rest of old top into a bin as an ordinary free chunk */
-  if (csp != old_top) {
-    mchunkptr q = (mchunkptr)old_top;
-    size_t psize = csp - old_top;
-    mchunkptr tn = chunk_plus_offset(q, psize);
-    set_free_with_pinuse(q, psize, tn);
-    insert_chunk(m, q, psize);
-  }
-
-  check_top_chunk(m, m->top);
-}
-
-/* -------------------------- System allocation -------------------------- */
-
-/* Get memory from system using MORECORE or MMAP */
-static void* sys_alloc(mstate m, size_t nb) {
-  char* tbase = CMFAIL;
-  size_t tsize = 0;
-  flag_t mmap_flag = 0;
-  size_t asize; /* allocation size */
-
-  ensure_initialization();
-
-  /* Directly map large chunks, but only if already initialized */
-  if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) {
-    void* mem = mmap_alloc(m, nb);
-    if (mem != 0)
-      return mem;
-  }
-
-  asize = granularity_align(nb + SYS_ALLOC_PADDING);
-  if (asize <= nb)
-    return 0; /* wraparound */
-  if (m->footprint_limit != 0) {
-    size_t fp = m->footprint + asize;
-    if (fp <= m->footprint || fp > m->footprint_limit)
-      return 0;
-  }
-
-  /*
-    Try getting memory in any of three ways (in most-preferred to
-    least-preferred order):
-    1. A call to MORECORE that can normally contiguously extend memory.
-       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
-       or main space is mmapped or a previous contiguous call failed)
-    2. A call to MMAP new space (disabled if not HAVE_MMAP).
-       Note that under the default settings, if MORECORE is unable to
-       fulfill a request, and HAVE_MMAP is true, then mmap is
-       used as a noncontiguous system allocator. This is a useful backup
-       strategy for systems with holes in address spaces -- in this case
-       sbrk cannot contiguously expand the heap, but mmap may be able to
-       find space.
-    3. A call to MORECORE that cannot usually contiguously extend memory.
-       (disabled if not HAVE_MORECORE)
-
-   In all cases, we need to request enough bytes from system to ensure
-   we can malloc nb bytes upon success, so pad with enough space for
-   top_foot, plus alignment-pad to make sure we don't lose bytes if
-   not on boundary, and round this up to a granularity unit.
-  */
-
-  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
-    char* br = CMFAIL;
-    size_t ssize = asize; /* sbrk call size */
-    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
-    ACQUIRE_MALLOC_GLOBAL_LOCK();
-
-    if (ss == 0) {  /* First time through or recovery */
-      char* base = (char*)CALL_MORECORE(0);
-      if (base != CMFAIL) {
-        size_t fp;
-        /* Adjust to end on a page boundary */
-        if (!is_page_aligned(base))
-          ssize += (page_align((size_t)base) - (size_t)base);
-        fp = m->footprint + ssize; /* recheck limits */
-        if (ssize > nb && ssize < HALF_MAX_SIZE_T &&
-            (m->footprint_limit == 0 ||
-             (fp > m->footprint && fp <= m->footprint_limit)) &&
-            (br = (char*)(CALL_MORECORE(ssize))) == base) {
-          tbase = base;
-          tsize = ssize;
-        }
-      }
-    }
-    else {
-      /* Subtract out existing available top space from MORECORE request. */
-      ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
-      /* Use mem here only if it did continuously extend old space */
-      if (ssize < HALF_MAX_SIZE_T &&
-          (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) {
-        tbase = br;
-        tsize = ssize;
-      }
-    }
-
-    if (tbase == CMFAIL) {    /* Cope with partial failure */
-      if (br != CMFAIL) {    /* Try to use/extend the space we did get */
-        if (ssize < HALF_MAX_SIZE_T &&
-            ssize < nb + SYS_ALLOC_PADDING) {
-          size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize);
-          if (esize < HALF_MAX_SIZE_T) {
-            char* end = (char*)CALL_MORECORE(esize);
-            if (end != CMFAIL)
-              ssize += esize;
-            else {            /* Can't use; try to release */
-              (void) CALL_MORECORE(-ssize);
-              br = CMFAIL;
-            }
-          }
-        }
-      }
-      if (br != CMFAIL) {    /* Use the space we did get */
-        tbase = br;
-        tsize = ssize;
-      }
-      else
-        disable_contiguous(m); /* Don't try contiguous path in the future */
-    }
-
-    RELEASE_MALLOC_GLOBAL_LOCK();
-  }
-
-  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */
-    char* mp = (char*)(CALL_MMAP(asize));
-    if (mp != CMFAIL) {
-      tbase = mp;
-      tsize = asize;
-      mmap_flag = USE_MMAP_BIT;
-    }
-  }
-
-  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
-    if (asize < HALF_MAX_SIZE_T) {
-      char* br = CMFAIL;
-      char* end = CMFAIL;
-      ACQUIRE_MALLOC_GLOBAL_LOCK();
-      br = (char*)(CALL_MORECORE(asize));
-      end = (char*)(CALL_MORECORE(0));
-      RELEASE_MALLOC_GLOBAL_LOCK();
-      if (br != CMFAIL && end != CMFAIL && br < end) {
-        size_t ssize = end - br;
-        if (ssize > nb + TOP_FOOT_SIZE) {
-          tbase = br;
-          tsize = ssize;
-        }
-      }
-    }
-  }
-
-  if (tbase != CMFAIL) {
-
-    if ((m->footprint += tsize) > m->max_footprint)
-      m->max_footprint = m->footprint;
-
-    if (!is_initialized(m)) { /* first-time initialization */
-      if (m->least_addr == 0 || tbase < m->least_addr)
-        m->least_addr = tbase;
-      m->seg.base = tbase;
-      m->seg.size = tsize;
-      m->seg.sflags = mmap_flag;
-      m->magic = mparams.magic;
-      m->release_checks = MAX_RELEASE_CHECK_RATE;
-      init_bins(m);
-#if !ONLY_MSPACES
-      if (is_global(m))
-        init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
-      else
-#endif
-      {
-        /* Offset top by embedded malloc_state */
-        mchunkptr mn = next_chunk(mem2chunk(m));
-        init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
-      }
-    }
-
-    else {
-      /* Try to merge with an existing segment */
-      msegmentptr sp = &m->seg;
-      /* Only consider most recent segment if traversal suppressed */
-      while (sp != 0 && tbase != sp->base + sp->size)
-        sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
-      if (sp != 0 &&
-          !is_extern_segment(sp) &&
-          (sp->sflags & USE_MMAP_BIT) == mmap_flag &&
-          segment_holds(sp, m->top)) { /* append */
-        sp->size += tsize;
-        init_top(m, m->top, m->topsize + tsize);
-      }
-      else {
-        if (tbase < m->least_addr)
-          m->least_addr = tbase;
-        sp = &m->seg;
-        while (sp != 0 && sp->base != tbase + tsize)
-          sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
-        if (sp != 0 &&
-            !is_extern_segment(sp) &&
-            (sp->sflags & USE_MMAP_BIT) == mmap_flag) {
-          char* oldbase = sp->base;
-          sp->base = tbase;
-          sp->size += tsize;
-          return prepend_alloc(m, tbase, oldbase, nb);
-        }
-        else
-          add_segment(m, tbase, tsize, mmap_flag);
-      }
-    }
-
-    if (nb < m->topsize) { /* Allocate from new or extended top space */
-      size_t rsize = m->topsize -= nb;
-      mchunkptr p = m->top;
-      mchunkptr r = m->top = chunk_plus_offset(p, nb);
-      r->head = rsize | PINUSE_BIT;
-      set_size_and_pinuse_of_inuse_chunk(m, p, nb);
-      check_top_chunk(m, m->top);
-      check_malloced_chunk(m, chunk2mem(p), nb);
-      return chunk2mem(p);
-    }
-  }
-
-  MALLOC_FAILURE_ACTION;
-  return 0;
-}
-
-/* -----------------------  system deallocation -------------------------- */
-
-/* Unmap and unlink any mmapped segments that don't contain used chunks */
-static size_t release_unused_segments(mstate m) {
-  size_t released = 0;
-  int nsegs = 0;
-  msegmentptr pred = &m->seg;
-  msegmentptr sp = pred->next;
-  while (sp != 0) {
-    char* base = sp->base;
-    size_t size = sp->size;
-    msegmentptr next = sp->next;
-    ++nsegs;
-    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
-      mchunkptr p = align_as_chunk(base);
-      size_t psize = chunksize(p);
-      /* Can unmap if first chunk holds entire segment and not pinned */
-      if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
-        tchunkptr tp = (tchunkptr)p;
-        assert(segment_holds(sp, (char*)sp));
-        if (p == m->dv) {
-          m->dv = 0;
-          m->dvsize = 0;
-        }
-        else {
-          unlink_large_chunk(m, tp);
-        }
-        if (CALL_MUNMAP(base, size) == 0) {
-          released += size;
-          m->footprint -= size;
-          /* unlink obsoleted record */
-          sp = pred;
-          sp->next = next;
-        }
-        else { /* back out if cannot unmap */
-          insert_large_chunk(m, tp, psize);
-        }
-      }
-    }
-    if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
-      break;
-    pred = sp;
-    sp = next;
-  }
-  /* Reset check counter */
-  m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)?
-                       (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE);
-  return released;
-}
-
-static int sys_trim(mstate m, size_t pad) {
-  size_t released = 0;
-  ensure_initialization();
-  if (pad < MAX_REQUEST && is_initialized(m)) {
-    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
-
-    if (m->topsize > pad) {
-      /* Shrink top space in granularity-size units, keeping at least one */
-      size_t unit = mparams.granularity;
-      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
-                      SIZE_T_ONE) * unit;
-      msegmentptr sp = segment_holding(m, (char*)m->top);
-
-      if (!is_extern_segment(sp)) {
-        if (is_mmapped_segment(sp)) {
-          if (HAVE_MMAP &&
-              sp->size >= extra &&
-              !has_segment_link(m, sp)) { /* can't shrink if pinned */
-            size_t newsize = sp->size - extra;
-            (void)newsize; /* placate people compiling -Wunused-variable */
-            /* Prefer mremap, fall back to munmap */
-            if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
-                (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
-              released = extra;
-            }
-          }
-        }
-        else if (HAVE_MORECORE) {
-          if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
-            extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
-          ACQUIRE_MALLOC_GLOBAL_LOCK();
-          {
-            /* Make sure end of memory is where we last set it. */
-            char* old_br = (char*)(CALL_MORECORE(0));
-            if (old_br == sp->base + sp->size) {
-              char* rel_br = (char*)(CALL_MORECORE(-extra));
-              char* new_br = (char*)(CALL_MORECORE(0));
-              if (rel_br != CMFAIL && new_br < old_br)
-                released = old_br - new_br;
-            }
-          }
-          RELEASE_MALLOC_GLOBAL_LOCK();
-        }
-      }
-
-      if (released != 0) {
-        sp->size -= released;
-        m->footprint -= released;
-        init_top(m, m->top, m->topsize - released);
-        check_top_chunk(m, m->top);
-      }
-    }
-
-    /* Unmap any unused mmapped segments */
-    if (HAVE_MMAP)
-      released += release_unused_segments(m);
-
-    /* On failure, disable autotrim to avoid repeated failed future calls */
-    if (released == 0 && m->topsize > m->trim_check)
-      m->trim_check = MAX_SIZE_T;
-  }
-
-  return (released != 0)? 1 : 0;
-}
-
-/* Consolidate and bin a chunk. Differs from exported versions
-   of free mainly in that the chunk need not be marked as inuse.
-*/
-static void dispose_chunk(mstate m, mchunkptr p, size_t psize) {
-  mchunkptr next = chunk_plus_offset(p, psize);
-  if (!pinuse(p)) {
-    mchunkptr prev;
-    size_t prevsize = p->prev_foot;
-    if (is_mmapped(p)) {
-      psize += prevsize + MMAP_FOOT_PAD;
-      if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
-        m->footprint -= psize;
-      return;
-    }
-    prev = chunk_minus_offset(p, prevsize);
-    psize += prevsize;
-    p = prev;
-    if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */
-      if (p != m->dv) {
-        unlink_chunk(m, p, prevsize);
-      }
-      else if ((next->head & INUSE_BITS) == INUSE_BITS) {
-        m->dvsize = psize;
-        set_free_with_pinuse(p, psize, next);
-        return;
-      }
-    }
-    else {
-      CORRUPTION_ERROR_ACTION(m);
-      return;
-    }
-  }
-  if (RTCHECK(ok_address(m, next))) {
-    if (!cinuse(next)) {  /* consolidate forward */
-      if (next == m->top) {
-        size_t tsize = m->topsize += psize;
-        m->top = p;
-        p->head = tsize | PINUSE_BIT;
-        if (p == m->dv) {
-          m->dv = 0;
-          m->dvsize = 0;
-        }
-        return;
-      }
-      else if (next == m->dv) {
-        size_t dsize = m->dvsize += psize;
-        m->dv = p;
-        set_size_and_pinuse_of_free_chunk(p, dsize);
-        return;
-      }
-      else {
-        size_t nsize = chunksize(next);
-        psize += nsize;
-        unlink_chunk(m, next, nsize);
-        set_size_and_pinuse_of_free_chunk(p, psize);
-        if (p == m->dv) {
-          m->dvsize = psize;
-          return;
-        }
-      }
-    }
-    else {
-      set_free_with_pinuse(p, psize, next);
-    }
-    insert_chunk(m, p, psize);
-  }
-  else {
-    CORRUPTION_ERROR_ACTION(m);
-  }
-}
-
-/* ---------------------------- malloc --------------------------- */
-
-/* allocate a large request from the best fitting chunk in a treebin */
-static void* tmalloc_large(mstate m, size_t nb) {
-  tchunkptr v = 0;
-  size_t rsize = -nb; /* Unsigned negation */
-  tchunkptr t;
-  bindex_t idx;
-  compute_tree_index(nb, idx);
-  if ((t = *treebin_at(m, idx)) != 0) {
-    /* Traverse tree for this bin looking for node with size == nb */
-    size_t sizebits = nb << leftshift_for_tree_index(idx);
-    tchunkptr rst = 0;  /* The deepest untaken right subtree */
-    for (;;) {
-      tchunkptr rt;
-      size_t trem = chunksize(t) - nb;
-      if (trem < rsize) {
-        v = t;
-        if ((rsize = trem) == 0)
-          break;
-      }
-      rt = t->child[1];
-      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
-      if (rt != 0 && rt != t)
-        rst = rt;
-      if (t == 0) {
-        t = rst; /* set t to least subtree holding sizes > nb */
-        break;
-      }
-      sizebits <<= 1;
-    }
-  }
-  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
-    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
-    if (leftbits != 0) {
-      bindex_t i;
-      binmap_t leastbit = least_bit(leftbits);
-      compute_bit2idx(leastbit, i);
-      t = *treebin_at(m, i);
-    }
-  }
-
-  while (t != 0) { /* find smallest of tree or subtree */
-    size_t trem = chunksize(t) - nb;
-    if (trem < rsize) {
-      rsize = trem;
-      v = t;
-    }
-    t = leftmost_child(t);
-  }
-
-  /*  If dv is a better fit, return 0 so malloc will use it */
-  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
-    if (RTCHECK(ok_address(m, v))) { /* split */
-      mchunkptr r = chunk_plus_offset(v, nb);
-      assert(chunksize(v) == rsize + nb);
-      if (RTCHECK(ok_next(v, r))) {
-        unlink_large_chunk(m, v);
-        if (rsize < MIN_CHUNK_SIZE)
-          set_inuse_and_pinuse(m, v, (rsize + nb));
-        else {
-          set_size_and_pinuse_of_inuse_chunk(m, v, nb);
-          set_size_and_pinuse_of_free_chunk(r, rsize);
-          insert_chunk(m, r, rsize);
-        }
-        return chunk2mem(v);
-      }
-    }
-    CORRUPTION_ERROR_ACTION(m);
-  }
-  return 0;
-}
-
-/* allocate a small request from the best fitting chunk in a treebin */
-static void* tmalloc_small(mstate m, size_t nb) {
-  tchunkptr t, v;
-  size_t rsize;
-  bindex_t i;
-  binmap_t leastbit = least_bit(m->treemap);
-  compute_bit2idx(leastbit, i);
-  v = t = *treebin_at(m, i);
-  rsize = chunksize(t) - nb;
-
-  while ((t = leftmost_child(t)) != 0) {
-    size_t trem = chunksize(t) - nb;
-    if (trem < rsize) {
-      rsize = trem;
-      v = t;
-    }
-  }
-
-  if (RTCHECK(ok_address(m, v))) {
-    mchunkptr r = chunk_plus_offset(v, nb);
-    assert(chunksize(v) == rsize + nb);
-    if (RTCHECK(ok_next(v, r))) {
-      unlink_large_chunk(m, v);
-      if (rsize < MIN_CHUNK_SIZE)
-        set_inuse_and_pinuse(m, v, (rsize + nb));
-      else {
-        set_size_and_pinuse_of_inuse_chunk(m, v, nb);
-        set_size_and_pinuse_of_free_chunk(r, rsize);
-        replace_dv(m, r, rsize);
-      }
-      return chunk2mem(v);
-    }
-  }
-
-  CORRUPTION_ERROR_ACTION(m);
-  return 0;
-}
-
-#if !ONLY_MSPACES
-
-void* dlmalloc(size_t bytes) {
-  /*
-     Basic algorithm:
-     If a small request (< 256 bytes minus per-chunk overhead):
-       1. If one exists, use a remainderless chunk in associated smallbin.
-          (Remainderless means that there are too few excess bytes to
-          represent as a chunk.)
-       2. If it is big enough, use the dv chunk, which is normally the
-          chunk adjacent to the one used for the most recent small request.
-       3. If one exists, split the smallest available chunk in a bin,
-          saving remainder in dv.
-       4. If it is big enough, use the top chunk.
-       5. If available, get memory from system and use it
-     Otherwise, for a large request:
-       1. Find the smallest available binned chunk that fits, and use it
-          if it is better fitting than dv chunk, splitting if necessary.
-       2. If better fitting than any binned chunk, use the dv chunk.
-       3. If it is big enough, use the top chunk.
-       4. If request size >= mmap threshold, try to directly mmap this chunk.
-       5. If available, get memory from system and use it
-
-     The ugly goto's here ensure that postaction occurs along all paths.
-  */
-
-#if USE_LOCKS
-  ensure_initialization(); /* initialize in sys_alloc if not using locks */
-#endif
-
-  if (!PREACTION(gm)) {
-    void* mem;
-    size_t nb;
-    if (bytes <= MAX_SMALL_REQUEST) {
-      bindex_t idx;
-      binmap_t smallbits;
-      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
-      idx = small_index(nb);
-      smallbits = gm->smallmap >> idx;
-
-      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
-        mchunkptr b, p;
-        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
-        b = smallbin_at(gm, idx);
-        p = b->fd;
-        assert(chunksize(p) == small_index2size(idx));
-        unlink_first_small_chunk(gm, b, p, idx);
-        set_inuse_and_pinuse(gm, p, small_index2size(idx));
-        mem = chunk2mem(p);
-        check_malloced_chunk(gm, mem, nb);
-        goto postaction;
-      }
-
-      else if (nb > gm->dvsize) {
-        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
-          mchunkptr b, p, r;
-          size_t rsize;
-          bindex_t i;
-          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
-          binmap_t leastbit = least_bit(leftbits);
-          compute_bit2idx(leastbit, i);
-          b = smallbin_at(gm, i);
-          p = b->fd;
-          assert(chunksize(p) == small_index2size(i));
-          unlink_first_small_chunk(gm, b, p, i);
-          rsize = small_index2size(i) - nb;
-          /* Fit here cannot be remainderless if 4byte sizes */
-          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
-            set_inuse_and_pinuse(gm, p, small_index2size(i));
-          else {
-            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
-            r = chunk_plus_offset(p, nb);
-            set_size_and_pinuse_of_free_chunk(r, rsize);
-            replace_dv(gm, r, rsize);
-          }
-          mem = chunk2mem(p);
-          check_malloced_chunk(gm, mem, nb);
-          goto postaction;
-        }
-
-        else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
-          check_malloced_chunk(gm, mem, nb);
-          goto postaction;
-        }
-      }
-    }
-    else if (bytes >= MAX_REQUEST)
-      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
-    else {
-      nb = pad_request(bytes);
-      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
-        check_malloced_chunk(gm, mem, nb);
-        goto postaction;
-      }
-    }
-
-    if (nb <= gm->dvsize) {
-      size_t rsize = gm->dvsize - nb;
-      mchunkptr p = gm->dv;
-      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
-        mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
-        gm->dvsize = rsize;
-        set_size_and_pinuse_of_free_chunk(r, rsize);
-        set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
-      }
-      else { /* exhaust dv */
-        size_t dvs = gm->dvsize;
-        gm->dvsize = 0;
-        gm->dv = 0;
-        set_inuse_and_pinuse(gm, p, dvs);
-      }
-      mem = chunk2mem(p);
-      check_malloced_chunk(gm, mem, nb);
-      goto postaction;
-    }
-
-    else if (nb < gm->topsize) { /* Split top */
-      size_t rsize = gm->topsize -= nb;
-      mchunkptr p = gm->top;
-      mchunkptr r = gm->top = chunk_plus_offset(p, nb);
-      r->head = rsize | PINUSE_BIT;
-      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
-      mem = chunk2mem(p);
-      check_top_chunk(gm, gm->top);
-      check_malloced_chunk(gm, mem, nb);
-      goto postaction;
-    }
-
-    mem = sys_alloc(gm, nb);
-
-  postaction:
-    POSTACTION(gm);
-    return mem;
-  }
-
-  return 0;
-}
-
-/* ---------------------------- free --------------------------- */
-
-void dlfree(void* mem) {
-  /*
-     Consolidate freed chunks with preceeding or succeeding bordering
-     free chunks, if they exist, and then place in a bin.  Intermixed
-     with special cases for top, dv, mmapped chunks, and usage errors.
-  */
-
-  if (mem != 0) {
-    mchunkptr p  = mem2chunk(mem);
-#if FOOTERS
-    mstate fm = get_mstate_for(p);
-    if (!ok_magic(fm)) {
-      USAGE_ERROR_ACTION(fm, p);
-      return;
-    }
-#else /* FOOTERS */
-#define fm gm
-#endif /* FOOTERS */
-    if (!PREACTION(fm)) {
-      check_inuse_chunk(fm, p);
-      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
-        size_t psize = chunksize(p);
-        mchunkptr next = chunk_plus_offset(p, psize);
-        if (!pinuse(p)) {
-          size_t prevsize = p->prev_foot;
-          if (is_mmapped(p)) {
-            psize += prevsize + MMAP_FOOT_PAD;
-            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
-              fm->footprint -= psize;
-            goto postaction;
-          }
-          else {
-            mchunkptr prev = chunk_minus_offset(p, prevsize);
-            psize += prevsize;
-            p = prev;
-            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
-              if (p != fm->dv) {
-                unlink_chunk(fm, p, prevsize);
-              }
-              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
-                fm->dvsize = psize;
-                set_free_with_pinuse(p, psize, next);
-                goto postaction;
-              }
-            }
-            else
-              goto erroraction;
-          }
-        }
-
-        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
-          if (!cinuse(next)) {  /* consolidate forward */
-            if (next == fm->top) {
-              size_t tsize = fm->topsize += psize;
-              fm->top = p;
-              p->head = tsize | PINUSE_BIT;
-              if (p == fm->dv) {
-                fm->dv = 0;
-                fm->dvsize = 0;
-              }
-              if (should_trim(fm, tsize))
-                sys_trim(fm, 0);
-              goto postaction;
-            }
-            else if (next == fm->dv) {
-              size_t dsize = fm->dvsize += psize;
-              fm->dv = p;
-              set_size_and_pinuse_of_free_chunk(p, dsize);
-              goto postaction;
-            }
-            else {
-              size_t nsize = chunksize(next);
-              psize += nsize;
-              unlink_chunk(fm, next, nsize);
-              set_size_and_pinuse_of_free_chunk(p, psize);
-              if (p == fm->dv) {
-                fm->dvsize = psize;
-                goto postaction;
-              }
-            }
-          }
-          else
-            set_free_with_pinuse(p, psize, next);
-
-          if (is_small(psize)) {
-            insert_small_chunk(fm, p, psize);
-            check_free_chunk(fm, p);
-          }
-          else {
-            tchunkptr tp = (tchunkptr)p;
-            insert_large_chunk(fm, tp, psize);
-            check_free_chunk(fm, p);
-            if (--fm->release_checks == 0)
-              release_unused_segments(fm);
-          }
-          goto postaction;
-        }
-      }
-    erroraction:
-      USAGE_ERROR_ACTION(fm, p);
-    postaction:
-      POSTACTION(fm);
-    }
-  }
-#if !FOOTERS
-#undef fm
-#endif /* FOOTERS */
-}
-
-void* dlcalloc(size_t n_elements, size_t elem_size) {
-  void* mem;
-  size_t req = 0;
-  if (n_elements != 0) {
-    req = n_elements * elem_size;
-    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
-        (req / n_elements != elem_size))
-      req = MAX_SIZE_T; /* force downstream failure on overflow */
-  }
-  mem = dlmalloc(req);
-  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
-    memset(mem, 0, req);
-  return mem;
-}
-
-#endif /* !ONLY_MSPACES */
-
-/* ------------ Internal support for realloc, memalign, etc -------------- */
-
-/* Try to realloc; only in-place unless can_move true */
-static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,
-                                   int can_move) {
-  mchunkptr newp = 0;
-  size_t oldsize = chunksize(p);
-  mchunkptr next = chunk_plus_offset(p, oldsize);
-  if (RTCHECK(ok_address(m, p) && ok_inuse(p) &&
-              ok_next(p, next) && ok_pinuse(next))) {
-    if (is_mmapped(p)) {
-      newp = mmap_resize(m, p, nb, can_move);
-    }
-    else if (oldsize >= nb) {             /* already big enough */
-      size_t rsize = oldsize - nb;
-      if (rsize >= MIN_CHUNK_SIZE) {      /* split off remainder */
-        mchunkptr r = chunk_plus_offset(p, nb);
-        set_inuse(m, p, nb);
-        set_inuse(m, r, rsize);
-        dispose_chunk(m, r, rsize);
-      }
-      newp = p;
-    }
-    else if (next == m->top) {  /* extend into top */
-      if (oldsize + m->topsize > nb) {
-        size_t newsize = oldsize + m->topsize;
-        size_t newtopsize = newsize - nb;
-        mchunkptr newtop = chunk_plus_offset(p, nb);
-        set_inuse(m, p, nb);
-        newtop->head = newtopsize |PINUSE_BIT;
-        m->top = newtop;
-        m->topsize = newtopsize;
-        newp = p;
-      }
-    }
-    else if (next == m->dv) { /* extend into dv */
-      size_t dvs = m->dvsize;
-      if (oldsize + dvs >= nb) {
-        size_t dsize = oldsize + dvs - nb;
-        if (dsize >= MIN_CHUNK_SIZE) {
-          mchunkptr r = chunk_plus_offset(p, nb);
-          mchunkptr n = chunk_plus_offset(r, dsize);
-          set_inuse(m, p, nb);
-          set_size_and_pinuse_of_free_chunk(r, dsize);
-          clear_pinuse(n);
-          m->dvsize = dsize;
-          m->dv = r;
-        }
-        else { /* exhaust dv */
-          size_t newsize = oldsize + dvs;
-          set_inuse(m, p, newsize);
-          m->dvsize = 0;
-          m->dv = 0;
-        }
-        newp = p;
-      }
-    }
-    else if (!cinuse(next)) { /* extend into next free chunk */
-      size_t nextsize = chunksize(next);
-      if (oldsize + nextsize >= nb) {
-        size_t rsize = oldsize + nextsize - nb;
-        unlink_chunk(m, next, nextsize);
-        if (rsize < MIN_CHUNK_SIZE) {
-          size_t newsize = oldsize + nextsize;
-          set_inuse(m, p, newsize);
-        }
-        else {
-          mchunkptr r = chunk_plus_offset(p, nb);
-          set_inuse(m, p, nb);
-          set_inuse(m, r, rsize);
-          dispose_chunk(m, r, rsize);
-        }
-        newp = p;
-      }
-    }
-  }
-  else {
-    USAGE_ERROR_ACTION(m, chunk2mem(p));
-  }
-  return newp;
-}
-
-static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
-  void* mem = 0;
-  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
-    alignment = MIN_CHUNK_SIZE;
-  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
-    size_t a = MALLOC_ALIGNMENT << 1;
-    while (a < alignment) a <<= 1;
-    alignment = a;
-  }
-  if (bytes >= MAX_REQUEST - alignment) {
-    if (m != 0)  { /* Test isn't needed but avoids compiler warning */
-      MALLOC_FAILURE_ACTION;
-    }
-  }
-  else {
-    size_t nb = request2size(bytes);
-    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
-    mem = internal_malloc(m, req);
-    if (mem != 0) {
-      mchunkptr p = mem2chunk(mem);
-      if (PREACTION(m))
-        return 0;
-      if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */
-        /*
-          Find an aligned spot inside chunk.  Since we need to give
-          back leading space in a chunk of at least MIN_CHUNK_SIZE, if
-          the first calculation places us at a spot with less than
-          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
-          We've allocated enough total room so that this is always
-          possible.
-        */
-        char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment -
-                                                       SIZE_T_ONE)) &
-                                             -alignment));
-        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
-          br : br+alignment;
-        mchunkptr newp = (mchunkptr)pos;
-        size_t leadsize = pos - (char*)(p);
-        size_t newsize = chunksize(p) - leadsize;
-
-        if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
-          newp->prev_foot = p->prev_foot + leadsize;
-          newp->head = newsize;
-        }
-        else { /* Otherwise, give back leader, use the rest */
-          set_inuse(m, newp, newsize);
-          set_inuse(m, p, leadsize);
-          dispose_chunk(m, p, leadsize);
-        }
-        p = newp;
-      }
-
-      /* Give back spare room at the end */
-      if (!is_mmapped(p)) {
-        size_t size = chunksize(p);
-        if (size > nb + MIN_CHUNK_SIZE) {
-          size_t remainder_size = size - nb;
-          mchunkptr remainder = chunk_plus_offset(p, nb);
-          set_inuse(m, p, nb);
-          set_inuse(m, remainder, remainder_size);
-          dispose_chunk(m, remainder, remainder_size);
-        }
-      }
-
-      mem = chunk2mem(p);
-      assert (chunksize(p) >= nb);
-      assert(((size_t)mem & (alignment - 1)) == 0);
-      check_inuse_chunk(m, p);
-      POSTACTION(m);
-    }
-  }
-  return mem;
-}
-
-/*
-  Common support for independent_X routines, handling
-    all of the combinations that can result.
-  The opts arg has:
-    bit 0 set if all elements are same size (using sizes[0])
-    bit 1 set if elements should be zeroed
-*/
-static void** ialloc(mstate m,
-                     size_t n_elements,
-                     size_t* sizes,
-                     int opts,
-                     void* chunks[]) {
-
-  size_t    element_size;   /* chunksize of each element, if all same */
-  size_t    contents_size;  /* total size of elements */
-  size_t    array_size;     /* request size of pointer array */
-  void*     mem;            /* malloced aggregate space */
-  mchunkptr p;              /* corresponding chunk */
-  size_t    remainder_size; /* remaining bytes while splitting */
-  void**    marray;         /* either "chunks" or malloced ptr array */
-  mchunkptr array_chunk;    /* chunk for malloced ptr array */
-  flag_t    was_enabled;    /* to disable mmap */
-  size_t    size;
-  size_t    i;
-
-  ensure_initialization();
-  /* compute array length, if needed */
-  if (chunks != 0) {
-    if (n_elements == 0)
-      return chunks; /* nothing to do */
-    marray = chunks;
-    array_size = 0;
-  }
-  else {
-    /* if empty req, must still return chunk representing empty array */
-    if (n_elements == 0)
-      return (void**)internal_malloc(m, 0);
-    marray = 0;
-    array_size = request2size(n_elements * (sizeof(void*)));
-  }
-
-  /* compute total element size */
-  if (opts & 0x1) { /* all-same-size */
-    element_size = request2size(*sizes);
-    contents_size = n_elements * element_size;
-  }
-  else { /* add up all the sizes */
-    element_size = 0;
-    contents_size = 0;
-    for (i = 0; i != n_elements; ++i)
-      contents_size += request2size(sizes[i]);
-  }
-
-  size = contents_size + array_size;
-
-  /*
-     Allocate the aggregate chunk.  First disable direct-mmapping so
-     malloc won't use it, since we would not be able to later
-     free/realloc space internal to a segregated mmap region.
-  */
-  was_enabled = use_mmap(m);
-  disable_mmap(m);
-  mem = internal_malloc(m, size - CHUNK_OVERHEAD);
-  if (was_enabled)
-    enable_mmap(m);
-  if (mem == 0)
-    return 0;
-
-  if (PREACTION(m)) return 0;
-  p = mem2chunk(mem);
-  remainder_size = chunksize(p);
-
-  assert(!is_mmapped(p));
-
-  if (opts & 0x2) {       /* optionally clear the elements */
-    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
-  }
-
-  /* If not provided, allocate the pointer array as final part of chunk */
-  if (marray == 0) {
-    size_t  array_chunk_size;
-    array_chunk = chunk_plus_offset(p, contents_size);
-    array_chunk_size = remainder_size - contents_size;
-    marray = (void**) (chunk2mem(array_chunk));
-    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
-    remainder_size = contents_size;
-  }
-
-  /* split out elements */
-  for (i = 0; ; ++i) {
-    marray[i] = chunk2mem(p);
-    if (i != n_elements-1) {
-      if (element_size != 0)
-        size = element_size;
-      else
-        size = request2size(sizes[i]);
-      remainder_size -= size;
-      set_size_and_pinuse_of_inuse_chunk(m, p, size);
-      p = chunk_plus_offset(p, size);
-    }
-    else { /* the final element absorbs any overallocation slop */
-      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
-      break;
-    }
-  }
-
-#if DEBUG
-  if (marray != chunks) {
-    /* final element must have exactly exhausted chunk */
-    if (element_size != 0) {
-      assert(remainder_size == element_size);
-    }
-    else {
-      assert(remainder_size == request2size(sizes[i]));
-    }
-    check_inuse_chunk(m, mem2chunk(marray));
-  }
-  for (i = 0; i != n_elements; ++i)
-    check_inuse_chunk(m, mem2chunk(marray[i]));
-
-#endif /* DEBUG */
-
-  POSTACTION(m);
-  return marray;
-}
-
-/* Try to free all pointers in the given array.
-   Note: this could be made faster, by delaying consolidation,
-   at the price of disabling some user integrity checks, We
-   still optimize some consolidations by combining adjacent
-   chunks before freeing, which will occur often if allocated
-   with ialloc or the array is sorted.
-*/
-static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) {
-  size_t unfreed = 0;
-  if (!PREACTION(m)) {
-    void** a;
-    void** fence = &(array[nelem]);
-    for (a = array; a != fence; ++a) {
-      void* mem = *a;
-      if (mem != 0) {
-        mchunkptr p = mem2chunk(mem);
-        size_t psize = chunksize(p);
-#if FOOTERS
-        if (get_mstate_for(p) != m) {
-          ++unfreed;
-          continue;
-        }
-#endif
-        check_inuse_chunk(m, p);
-        *a = 0;
-        if (RTCHECK(ok_address(m, p) && ok_inuse(p))) {
-          void ** b = a + 1; /* try to merge with next chunk */
-          mchunkptr next = next_chunk(p);
-          if (b != fence && *b == chunk2mem(next)) {
-            size_t newsize = chunksize(next) + psize;
-            set_inuse(m, p, newsize);
-            *b = chunk2mem(p);
-          }
-          else
-            dispose_chunk(m, p, psize);
-        }
-        else {
-          CORRUPTION_ERROR_ACTION(m);
-          break;
-        }
-      }
-    }
-    if (should_trim(m, m->topsize))
-      sys_trim(m, 0);
-    POSTACTION(m);
-  }
-  return unfreed;
-}
-
-/* Traversal */
-#if MALLOC_INSPECT_ALL
-static void internal_inspect_all(mstate m,
-                                 void(*handler)(void *start,
-                                                void *end,
-                                                size_t used_bytes,
-                                                void* callback_arg),
-                                 void* arg) {
-  if (is_initialized(m)) {
-    mchunkptr top = m->top;
-    msegmentptr s;
-    for (s = &m->seg; s != 0; s = s->next) {
-      mchunkptr q = align_as_chunk(s->base);
-      while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) {
-        mchunkptr next = next_chunk(q);
-        size_t sz = chunksize(q);
-        size_t used;
-        void* start;
-        if (is_inuse(q)) {
-          used = sz - CHUNK_OVERHEAD; /* must not be mmapped */
-          start = chunk2mem(q);
-        }
-        else {
-          used = 0;
-          if (is_small(sz)) {     /* offset by possible bookkeeping */
-            start = (void*)((char*)q + sizeof(struct malloc_chunk));
-          }
-          else {
-            start = (void*)((char*)q + sizeof(struct malloc_tree_chunk));
-          }
-        }
-        if (start < (void*)next)  /* skip if all space is bookkeeping */
-          handler(start, next, used, arg);
-        if (q == top)
-          break;
-        q = next;
-      }
-    }
-  }
-}
-#endif /* MALLOC_INSPECT_ALL */
-
-/* ------------------ Exported realloc, memalign, etc -------------------- */
-
-#if !ONLY_MSPACES
-
-void* dlrealloc(void* oldmem, size_t bytes) {
-  void* mem = 0;
-  if (oldmem == 0) {
-    mem = dlmalloc(bytes);
-  }
-  else if (bytes >= MAX_REQUEST) {
-    MALLOC_FAILURE_ACTION;
-  }
-#ifdef REALLOC_ZERO_BYTES_FREES
-  else if (bytes == 0) {
-    dlfree(oldmem);
-  }
-#endif /* REALLOC_ZERO_BYTES_FREES */
-  else {
-    size_t nb = request2size(bytes);
-    mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
-    mstate m = gm;
-#else /* FOOTERS */
-    mstate m = get_mstate_for(oldp);
-    if (!ok_magic(m)) {
-      USAGE_ERROR_ACTION(m, oldmem);
-      return 0;
-    }
-#endif /* FOOTERS */
-    if (!PREACTION(m)) {
-      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
-      POSTACTION(m);
-      if (newp != 0) {
-        check_inuse_chunk(m, newp);
-        mem = chunk2mem(newp);
-      }
-      else {
-        mem = internal_malloc(m, bytes);
-        if (mem != 0) {
-          size_t oc = chunksize(oldp) - overhead_for(oldp);
-          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
-          internal_free(m, oldmem);
-        }
-      }
-    }
-  }
-  return mem;
-}
-
-void* dlrealloc_in_place(void* oldmem, size_t bytes) {
-  void* mem = 0;
-  if (oldmem != 0) {
-    if (bytes >= MAX_REQUEST) {
-      MALLOC_FAILURE_ACTION;
-    }
-    else {
-      size_t nb = request2size(bytes);
-      mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
-      mstate m = gm;
-#else /* FOOTERS */
-      mstate m = get_mstate_for(oldp);
-      if (!ok_magic(m)) {
-        USAGE_ERROR_ACTION(m, oldmem);
-        return 0;
-      }
-#endif /* FOOTERS */
-      if (!PREACTION(m)) {
-        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
-        POSTACTION(m);
-        if (newp == oldp) {
-          check_inuse_chunk(m, newp);
-          mem = oldmem;
-        }
-      }
-    }
-  }
-  return mem;
-}
-
-void* dlmemalign(size_t alignment, size_t bytes) {
-  if (alignment <= MALLOC_ALIGNMENT) {
-    return dlmalloc(bytes);
-  }
-  return internal_memalign(gm, alignment, bytes);
-}
-
-int dlposix_memalign(void** pp, size_t alignment, size_t bytes) {
-  void* mem = 0;
-  if (alignment == MALLOC_ALIGNMENT)
-    mem = dlmalloc(bytes);
-  else {
-    size_t d = alignment / sizeof(void*);
-    size_t r = alignment % sizeof(void*);
-    if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0)
-      return EINVAL;
-    else if (bytes <= MAX_REQUEST - alignment) {
-      if (alignment <  MIN_CHUNK_SIZE)
-        alignment = MIN_CHUNK_SIZE;
-      mem = internal_memalign(gm, alignment, bytes);
-    }
-  }
-  if (mem == 0)
-    return ENOMEM;
-  else {
-    *pp = mem;
-    return 0;
-  }
-}
-
-void* dlvalloc(size_t bytes) {
-  size_t pagesz;
-  ensure_initialization();
-  pagesz = mparams.page_size;
-  return dlmemalign(pagesz, bytes);
-}
-
-void* dlpvalloc(size_t bytes) {
-  size_t pagesz;
-  ensure_initialization();
-  pagesz = mparams.page_size;
-  return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
-}
-
-void** dlindependent_calloc(size_t n_elements, size_t elem_size,
-                            void* chunks[]) {
-  size_t sz = elem_size; /* serves as 1-element array */
-  return ialloc(gm, n_elements, &sz, 3, chunks);
-}
-
-void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
-                              void* chunks[]) {
-  return ialloc(gm, n_elements, sizes, 0, chunks);
-}
-
-size_t dlbulk_free(void* array[], size_t nelem) {
-  return internal_bulk_free(gm, array, nelem);
-}
-
-#if MALLOC_INSPECT_ALL
-void dlmalloc_inspect_all(void(*handler)(void *start,
-                                         void *end,
-                                         size_t used_bytes,
-                                         void* callback_arg),
-                          void* arg) {
-  ensure_initialization();
-  if (!PREACTION(gm)) {
-    internal_inspect_all(gm, handler, arg);
-    POSTACTION(gm);
-  }
-}
-#endif /* MALLOC_INSPECT_ALL */
-
-int dlmalloc_trim(size_t pad) {
-  int result = 0;
-  ensure_initialization();
-  if (!PREACTION(gm)) {
-    result = sys_trim(gm, pad);
-    POSTACTION(gm);
-  }
-  return result;
-}
-
-size_t dlmalloc_footprint(void) {
-  return gm->footprint;
-}
-
-size_t dlmalloc_max_footprint(void) {
-  return gm->max_footprint;
-}
-
-size_t dlmalloc_footprint_limit(void) {
-  size_t maf = gm->footprint_limit;
-  return maf == 0 ? MAX_SIZE_T : maf;
-}
-
-size_t dlmalloc_set_footprint_limit(size_t bytes) {
-  size_t result;  /* invert sense of 0 */
-  if (bytes == 0)
-    result = granularity_align(1); /* Use minimal size */
-  if (bytes == MAX_SIZE_T)
-    result = 0;                    /* disable */
-  else
-    result = granularity_align(bytes);
-  return gm->footprint_limit = result;
-}
-
-#if !NO_MALLINFO
-struct mallinfo dlmallinfo(void) {
-  return internal_mallinfo(gm);
-}
-#endif /* NO_MALLINFO */
-
-#if !NO_MALLOC_STATS
-void dlmalloc_stats() {
-  internal_malloc_stats(gm);
-}
-#endif /* NO_MALLOC_STATS */
-
-int dlmallopt(int param_number, int value) {
-  return change_mparam(param_number, value);
-}
-
-size_t dlmalloc_usable_size(void* mem) {
-  if (mem != 0) {
-    mchunkptr p = mem2chunk(mem);
-    if (is_inuse(p))
-      return chunksize(p) - overhead_for(p);
-  }
-  return 0;
-}
-
-#endif /* !ONLY_MSPACES */
-
-/* ----------------------------- user mspaces ---------------------------- */
-
-#if MSPACES
-
-static mstate init_user_mstate(char* tbase, size_t tsize) {
-  size_t msize = pad_request(sizeof(struct malloc_state));
-  mchunkptr mn;
-  mchunkptr msp = align_as_chunk(tbase);
-  mstate m = (mstate)(chunk2mem(msp));
-  memset(m, 0, msize);
-  (void)INITIAL_LOCK(&m->mutex);
-  msp->head = (msize|INUSE_BITS);
-  m->seg.base = m->least_addr = tbase;
-  m->seg.size = m->footprint = m->max_footprint = tsize;
-  m->magic = mparams.magic;
-  m->release_checks = MAX_RELEASE_CHECK_RATE;
-  m->mflags = mparams.default_mflags;
-  m->extp = 0;
-  m->exts = 0;
-  disable_contiguous(m);
-  init_bins(m);
-  mn = next_chunk(mem2chunk(m));
-  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
-  check_top_chunk(m, m->top);
-  return m;
-}
-
-mspace create_mspace(size_t capacity, int locked) {
-  mstate m = 0;
-  size_t msize;
-  ensure_initialization();
-  msize = pad_request(sizeof(struct malloc_state));
-  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
-    size_t rs = ((capacity == 0)? mparams.granularity :
-                 (capacity + TOP_FOOT_SIZE + msize));
-    size_t tsize = granularity_align(rs);
-    char* tbase = (char*)(CALL_MMAP(tsize));
-    if (tbase != CMFAIL) {
-      m = init_user_mstate(tbase, tsize);
-      m->seg.sflags = USE_MMAP_BIT;
-      set_lock(m, locked);
-    }
-  }
-  return (mspace)m;
-}
-
-mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
-  mstate m = 0;
-  size_t msize;
-  ensure_initialization();
-  msize = pad_request(sizeof(struct malloc_state));
-  if (capacity > msize + TOP_FOOT_SIZE &&
-      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
-    m = init_user_mstate((char*)base, capacity);
-    m->seg.sflags = EXTERN_BIT;
-    set_lock(m, locked);
-  }
-  return (mspace)m;
-}
-
-int mspace_track_large_chunks(mspace msp, int enable) {
-  int ret = 0;
-  mstate ms = (mstate)msp;
-  if (!PREACTION(ms)) {
-    if (!use_mmap(ms)) {
-      ret = 1;
-    }
-    if (!enable) {
-      enable_mmap(ms);
-    } else {
-      disable_mmap(ms);
-    }
-    POSTACTION(ms);
-  }
-  return ret;
-}
-
-size_t destroy_mspace(mspace msp) {
-  size_t freed = 0;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    msegmentptr sp = &ms->seg;
-    (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */
-    while (sp != 0) {
-      char* base = sp->base;
-      size_t size = sp->size;
-      flag_t flag = sp->sflags;
-      (void)base; /* placate people compiling -Wunused-variable */
-      sp = sp->next;
-      if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&
-          CALL_MUNMAP(base, size) == 0)
-        freed += size;
-    }
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return freed;
-}
-
-/*
-  mspace versions of routines are near-clones of the global
-  versions. This is not so nice but better than the alternatives.
-*/
-
-void* mspace_malloc(mspace msp, size_t bytes) {
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  if (!PREACTION(ms)) {
-    void* mem;
-    size_t nb;
-    if (bytes <= MAX_SMALL_REQUEST) {
-      bindex_t idx;
-      binmap_t smallbits;
-      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
-      idx = small_index(nb);
-      smallbits = ms->smallmap >> idx;
-
-      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
-        mchunkptr b, p;
-        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
-        b = smallbin_at(ms, idx);
-        p = b->fd;
-        assert(chunksize(p) == small_index2size(idx));
-        unlink_first_small_chunk(ms, b, p, idx);
-        set_inuse_and_pinuse(ms, p, small_index2size(idx));
-        mem = chunk2mem(p);
-        check_malloced_chunk(ms, mem, nb);
-        goto postaction;
-      }
-
-      else if (nb > ms->dvsize) {
-        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
-          mchunkptr b, p, r;
-          size_t rsize;
-          bindex_t i;
-          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
-          binmap_t leastbit = least_bit(leftbits);
-          compute_bit2idx(leastbit, i);
-          b = smallbin_at(ms, i);
-          p = b->fd;
-          assert(chunksize(p) == small_index2size(i));
-          unlink_first_small_chunk(ms, b, p, i);
-          rsize = small_index2size(i) - nb;
-          /* Fit here cannot be remainderless if 4byte sizes */
-          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
-            set_inuse_and_pinuse(ms, p, small_index2size(i));
-          else {
-            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
-            r = chunk_plus_offset(p, nb);
-            set_size_and_pinuse_of_free_chunk(r, rsize);
-            replace_dv(ms, r, rsize);
-          }
-          mem = chunk2mem(p);
-          check_malloced_chunk(ms, mem, nb);
-          goto postaction;
-        }
-
-        else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
-          check_malloced_chunk(ms, mem, nb);
-          goto postaction;
-        }
-      }
-    }
-    else if (bytes >= MAX_REQUEST)
-      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
-    else {
-      nb = pad_request(bytes);
-      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
-        check_malloced_chunk(ms, mem, nb);
-        goto postaction;
-      }
-    }
-
-    if (nb <= ms->dvsize) {
-      size_t rsize = ms->dvsize - nb;
-      mchunkptr p = ms->dv;
-      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
-        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
-        ms->dvsize = rsize;
-        set_size_and_pinuse_of_free_chunk(r, rsize);
-        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
-      }
-      else { /* exhaust dv */
-        size_t dvs = ms->dvsize;
-        ms->dvsize = 0;
-        ms->dv = 0;
-        set_inuse_and_pinuse(ms, p, dvs);
-      }
-      mem = chunk2mem(p);
-      check_malloced_chunk(ms, mem, nb);
-      goto postaction;
-    }
-
-    else if (nb < ms->topsize) { /* Split top */
-      size_t rsize = ms->topsize -= nb;
-      mchunkptr p = ms->top;
-      mchunkptr r = ms->top = chunk_plus_offset(p, nb);
-      r->head = rsize | PINUSE_BIT;
-      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
-      mem = chunk2mem(p);
-      check_top_chunk(ms, ms->top);
-      check_malloced_chunk(ms, mem, nb);
-      goto postaction;
-    }
-
-    mem = sys_alloc(ms, nb);
-
-  postaction:
-    POSTACTION(ms);
-    return mem;
-  }
-
-  return 0;
-}
-
-void mspace_free(mspace msp, void* mem) {
-  if (mem != 0) {
-    mchunkptr p  = mem2chunk(mem);
-#if FOOTERS
-    mstate fm = get_mstate_for(p);
-    (void)msp; /* placate people compiling -Wunused */
-#else /* FOOTERS */
-    mstate fm = (mstate)msp;
-#endif /* FOOTERS */
-    if (!ok_magic(fm)) {
-      USAGE_ERROR_ACTION(fm, p);
-      return;
-    }
-    if (!PREACTION(fm)) {
-      check_inuse_chunk(fm, p);
-      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
-        size_t psize = chunksize(p);
-        mchunkptr next = chunk_plus_offset(p, psize);
-        if (!pinuse(p)) {
-          size_t prevsize = p->prev_foot;
-          if (is_mmapped(p)) {
-            psize += prevsize + MMAP_FOOT_PAD;
-            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
-              fm->footprint -= psize;
-            goto postaction;
-          }
-          else {
-            mchunkptr prev = chunk_minus_offset(p, prevsize);
-            psize += prevsize;
-            p = prev;
-            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
-              if (p != fm->dv) {
-                unlink_chunk(fm, p, prevsize);
-              }
-              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
-                fm->dvsize = psize;
-                set_free_with_pinuse(p, psize, next);
-                goto postaction;
-              }
-            }
-            else
-              goto erroraction;
-          }
-        }
-
-        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
-          if (!cinuse(next)) {  /* consolidate forward */
-            if (next == fm->top) {
-              size_t tsize = fm->topsize += psize;
-              fm->top = p;
-              p->head = tsize | PINUSE_BIT;
-              if (p == fm->dv) {
-                fm->dv = 0;
-                fm->dvsize = 0;
-              }
-              if (should_trim(fm, tsize))
-                sys_trim(fm, 0);
-              goto postaction;
-            }
-            else if (next == fm->dv) {
-              size_t dsize = fm->dvsize += psize;
-              fm->dv = p;
-              set_size_and_pinuse_of_free_chunk(p, dsize);
-              goto postaction;
-            }
-            else {
-              size_t nsize = chunksize(next);
-              psize += nsize;
-              unlink_chunk(fm, next, nsize);
-              set_size_and_pinuse_of_free_chunk(p, psize);
-              if (p == fm->dv) {
-                fm->dvsize = psize;
-                goto postaction;
-              }
-            }
-          }
-          else
-            set_free_with_pinuse(p, psize, next);
-
-          if (is_small(psize)) {
-            insert_small_chunk(fm, p, psize);
-            check_free_chunk(fm, p);
-          }
-          else {
-            tchunkptr tp = (tchunkptr)p;
-            insert_large_chunk(fm, tp, psize);
-            check_free_chunk(fm, p);
-            if (--fm->release_checks == 0)
-              release_unused_segments(fm);
-          }
-          goto postaction;
-        }
-      }
-    erroraction:
-      USAGE_ERROR_ACTION(fm, p);
-    postaction:
-      POSTACTION(fm);
-    }
-  }
-}
-
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
-  void* mem;
-  size_t req = 0;
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  if (n_elements != 0) {
-    req = n_elements * elem_size;
-    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
-        (req / n_elements != elem_size))
-      req = MAX_SIZE_T; /* force downstream failure on overflow */
-  }
-  mem = internal_malloc(ms, req);
-  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
-    memset(mem, 0, req);
-  return mem;
-}
-
-void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
-  void* mem = 0;
-  if (oldmem == 0) {
-    mem = mspace_malloc(msp, bytes);
-  }
-  else if (bytes >= MAX_REQUEST) {
-    MALLOC_FAILURE_ACTION;
-  }
-#ifdef REALLOC_ZERO_BYTES_FREES
-  else if (bytes == 0) {
-    mspace_free(msp, oldmem);
-  }
-#endif /* REALLOC_ZERO_BYTES_FREES */
-  else {
-    size_t nb = request2size(bytes);
-    mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
-    mstate m = (mstate)msp;
-#else /* FOOTERS */
-    mstate m = get_mstate_for(oldp);
-    if (!ok_magic(m)) {
-      USAGE_ERROR_ACTION(m, oldmem);
-      return 0;
-    }
-#endif /* FOOTERS */
-    if (!PREACTION(m)) {
-      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
-      POSTACTION(m);
-      if (newp != 0) {
-        check_inuse_chunk(m, newp);
-        mem = chunk2mem(newp);
-      }
-      else {
-        mem = mspace_malloc(m, bytes);
-        if (mem != 0) {
-          size_t oc = chunksize(oldp) - overhead_for(oldp);
-          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
-          mspace_free(m, oldmem);
-        }
-      }
-    }
-  }
-  return mem;
-}
-
-void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) {
-  void* mem = 0;
-  if (oldmem != 0) {
-    if (bytes >= MAX_REQUEST) {
-      MALLOC_FAILURE_ACTION;
-    }
-    else {
-      size_t nb = request2size(bytes);
-      mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
-      mstate m = (mstate)msp;
-#else /* FOOTERS */
-      mstate m = get_mstate_for(oldp);
-      (void)msp; /* placate people compiling -Wunused */
-      if (!ok_magic(m)) {
-        USAGE_ERROR_ACTION(m, oldmem);
-        return 0;
-      }
-#endif /* FOOTERS */
-      if (!PREACTION(m)) {
-        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
-        POSTACTION(m);
-        if (newp == oldp) {
-          check_inuse_chunk(m, newp);
-          mem = oldmem;
-        }
-      }
-    }
-  }
-  return mem;
-}
-
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  if (alignment <= MALLOC_ALIGNMENT)
-    return mspace_malloc(msp, bytes);
-  return internal_memalign(ms, alignment, bytes);
-}
-
-void** mspace_independent_calloc(mspace msp, size_t n_elements,
-                                 size_t elem_size, void* chunks[]) {
-  size_t sz = elem_size; /* serves as 1-element array */
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  return ialloc(ms, n_elements, &sz, 3, chunks);
-}
-
-void** mspace_independent_comalloc(mspace msp, size_t n_elements,
-                                   size_t sizes[], void* chunks[]) {
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-    return 0;
-  }
-  return ialloc(ms, n_elements, sizes, 0, chunks);
-}
-
-size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) {
-  return internal_bulk_free((mstate)msp, array, nelem);
-}
-
-#if MALLOC_INSPECT_ALL
-void mspace_inspect_all(mspace msp,
-                        void(*handler)(void *start,
-                                       void *end,
-                                       size_t used_bytes,
-                                       void* callback_arg),
-                        void* arg) {
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    if (!PREACTION(ms)) {
-      internal_inspect_all(ms, handler, arg);
-      POSTACTION(ms);
-    }
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-}
-#endif /* MALLOC_INSPECT_ALL */
-
-int mspace_trim(mspace msp, size_t pad) {
-  int result = 0;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    if (!PREACTION(ms)) {
-      result = sys_trim(ms, pad);
-      POSTACTION(ms);
-    }
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return result;
-}
-
-#if !NO_MALLOC_STATS
-void mspace_malloc_stats(mspace msp) {
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    internal_malloc_stats(ms);
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-}
-#endif /* NO_MALLOC_STATS */
-
-size_t mspace_footprint(mspace msp) {
-  size_t result = 0;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    result = ms->footprint;
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return result;
-}
-
-size_t mspace_max_footprint(mspace msp) {
-  size_t result = 0;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    result = ms->max_footprint;
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return result;
-}
-
-size_t mspace_footprint_limit(mspace msp) {
-  size_t result = 0;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    size_t maf = ms->footprint_limit;
-    result = (maf == 0) ? MAX_SIZE_T : maf;
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return result;
-}
-
-size_t mspace_set_footprint_limit(mspace msp, size_t bytes) {
-  size_t result = 0;
-  mstate ms = (mstate)msp;
-  if (ok_magic(ms)) {
-    if (bytes == 0)
-      result = granularity_align(1); /* Use minimal size */
-    if (bytes == MAX_SIZE_T)
-      result = 0;                    /* disable */
-    else
-      result = granularity_align(bytes);
-    ms->footprint_limit = result;
-  }
-  else {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return result;
-}
-
-#if !NO_MALLINFO
-struct mallinfo mspace_mallinfo(mspace msp) {
-  mstate ms = (mstate)msp;
-  if (!ok_magic(ms)) {
-    USAGE_ERROR_ACTION(ms,ms);
-  }
-  return internal_mallinfo(ms);
-}
-#endif /* NO_MALLINFO */
-
-size_t mspace_usable_size(const void* mem) {
-  if (mem != 0) {
-    mchunkptr p = mem2chunk(mem);
-    if (is_inuse(p))
-      return chunksize(p) - overhead_for(p);
-  }
-  return 0;
-}
-
-int mspace_mallopt(int param_number, int value) {
-  return change_mparam(param_number, value);
-}
-
-#endif /* MSPACES */
-
-
-/* -------------------- Alternative MORECORE functions ------------------- */
-
-/*
-  Guidelines for creating a custom version of MORECORE:
-
-  * For best performance, MORECORE should allocate in multiples of pagesize.
-  * MORECORE may allocate more memory than requested. (Or even less,
-      but this will usually result in a malloc failure.)
-  * MORECORE must not allocate memory when given argument zero, but
-      instead return one past the end address of memory from previous
-      nonzero call.
-  * For best performance, consecutive calls to MORECORE with positive
-      arguments should return increasing addresses, indicating that
-      space has been contiguously extended.
-  * Even though consecutive calls to MORECORE need not return contiguous
-      addresses, it must be OK for malloc'ed chunks to span multiple
-      regions in those cases where they do happen to be contiguous.
-  * MORECORE need not handle negative arguments -- it may instead
-      just return MFAIL when given negative arguments.
-      Negative arguments are always multiples of pagesize. MORECORE
-      must not misinterpret negative args as large positive unsigned
-      args. You can suppress all such calls from even occurring by defining
-      MORECORE_CANNOT_TRIM,
-
-  As an example alternative MORECORE, here is a custom allocator
-  kindly contributed for pre-OSX macOS.  It uses virtually but not
-  necessarily physically contiguous non-paged memory (locked in,
-  present and won't get swapped out).  You can use it by uncommenting
-  this section, adding some #includes, and setting up the appropriate
-  defines above:
-
-      #define MORECORE osMoreCore
-
-  There is also a shutdown routine that should somehow be called for
-  cleanup upon program exit.
-
-  #define MAX_POOL_ENTRIES 100
-  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)
-  static int next_os_pool;
-  void *our_os_pools[MAX_POOL_ENTRIES];
-
-  void *osMoreCore(int size)
-  {
-    void *ptr = 0;
-    static void *sbrk_top = 0;
-
-    if (size > 0)
-    {
-      if (size < MINIMUM_MORECORE_SIZE)
-         size = MINIMUM_MORECORE_SIZE;
-      if (CurrentExecutionLevel() == kTaskLevel)
-         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
-      if (ptr == 0)
-      {
-        return (void *) MFAIL;
-      }
-      // save ptrs so they can be freed during cleanup
-      our_os_pools[next_os_pool] = ptr;
-      next_os_pool++;
-      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
-      sbrk_top = (char *) ptr + size;
-      return ptr;
-    }
-    else if (size < 0)
-    {
-      // we don't currently support shrink behavior
-      return (void *) MFAIL;
-    }
-    else
-    {
-      return sbrk_top;
-    }
-  }
-
-  // cleanup any allocated memory pools
-  // called as last thing before shutting down driver
-
-  void osCleanupMem(void)
-  {
-    void **ptr;
-
-    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
-      if (*ptr)
-      {
-         PoolDeallocate(*ptr);
-         *ptr = 0;
-      }
-  }
-
-*/
-
-
-/* -----------------------------------------------------------------------
-History:
-    v2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea
-      * fix bad comparison in dlposix_memalign
-      * don't reuse adjusted asize in sys_alloc
-      * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion
-      * reduce compiler warnings -- thanks to all who reported/suggested these
-
-    v2.8.5 Sun May 22 10:26:02 2011  Doug Lea  (dl at gee)
-      * Always perform unlink checks unless INSECURE
-      * Add posix_memalign.
-      * Improve realloc to expand in more cases; expose realloc_in_place.
-        Thanks to Peter Buhr for the suggestion.
-      * Add footprint_limit, inspect_all, bulk_free. Thanks
-        to Barry Hayes and others for the suggestions.
-      * Internal refactorings to avoid calls while holding locks
-      * Use non-reentrant locks by default. Thanks to Roland McGrath
-        for the suggestion.
-      * Small fixes to mspace_destroy, reset_on_error.
-      * Various configuration extensions/changes. Thanks
-         to all who contributed these.
-
-    V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu)
-      * Update Creative Commons URL
-
-    V2.8.4 Wed May 27 09:56:23 2009  Doug Lea  (dl at gee)
-      * Use zeros instead of prev foot for is_mmapped
-      * Add mspace_track_large_chunks; thanks to Jean Brouwers
-      * Fix set_inuse in internal_realloc; thanks to Jean Brouwers
-      * Fix insufficient sys_alloc padding when using 16byte alignment
-      * Fix bad error check in mspace_footprint
-      * Adaptations for ptmalloc; thanks to Wolfram Gloger.
-      * Reentrant spin locks; thanks to Earl Chew and others
-      * Win32 improvements; thanks to Niall Douglas and Earl Chew
-      * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
-      * Extension hook in malloc_state
-      * Various small adjustments to reduce warnings on some compilers
-      * Various configuration extensions/changes for more platforms. Thanks
-         to all who contributed these.
-
-    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)
-      * Add max_footprint functions
-      * Ensure all appropriate literals are size_t
-      * Fix conditional compilation problem for some #define settings
-      * Avoid concatenating segments with the one provided
-        in create_mspace_with_base
-      * Rename some variables to avoid compiler shadowing warnings
-      * Use explicit lock initialization.
-      * Better handling of sbrk interference.
-      * Simplify and fix segment insertion, trimming and mspace_destroy
-      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
-      * Thanks especially to Dennis Flanagan for help on these.
-
-    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)
-      * Fix memalign brace error.
-
-    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)
-      * Fix improper #endif nesting in C++
-      * Add explicit casts needed for C++
-
-    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)
-      * Use trees for large bins
-      * Support mspaces
-      * Use segments to unify sbrk-based and mmap-based system allocation,
-        removing need for emulation on most platforms without sbrk.
-      * Default safety checks
-      * Optional footer checks. Thanks to William Robertson for the idea.
-      * Internal code refactoring
-      * Incorporate suggestions and platform-specific changes.
-        Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
-        Aaron Bachmann,  Emery Berger, and others.
-      * Speed up non-fastbin processing enough to remove fastbins.
-      * Remove useless cfree() to avoid conflicts with other apps.
-      * Remove internal memcpy, memset. Compilers handle builtins better.
-      * Remove some options that no one ever used and rename others.
-
-    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)
-      * Fix malloc_state bitmap array misdeclaration
-
-    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)
-      * Allow tuning of FIRST_SORTED_BIN_SIZE
-      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
-      * Better detection and support for non-contiguousness of MORECORE.
-        Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
-      * Bypass most of malloc if no frees. Thanks To Emery Berger.
-      * Fix freeing of old top non-contiguous chunk im sysmalloc.
-      * Raised default trim and map thresholds to 256K.
-      * Fix mmap-related #defines. Thanks to Lubos Lunak.
-      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
-      * Branch-free bin calculation
-      * Default trim and mmap thresholds now 256K.
-
-    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
-      * Introduce independent_comalloc and independent_calloc.
-        Thanks to Michael Pachos for motivation and help.
-      * Make optional .h file available
-      * Allow > 2GB requests on 32bit systems.
-      * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
-        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
-        and Anonymous.
-      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
-        helping test this.)
-      * memalign: check alignment arg
-      * realloc: don't try to shift chunks backwards, since this
-        leads to  more fragmentation in some programs and doesn't
-        seem to help in any others.
-      * Collect all cases in malloc requiring system memory into sysmalloc
-      * Use mmap as backup to sbrk
-      * Place all internal state in malloc_state
-      * Introduce fastbins (although similar to 2.5.1)
-      * Many minor tunings and cosmetic improvements
-      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
-      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
-        Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
-      * Include errno.h to support default failure action.
-
-    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
-      * return null for negative arguments
-      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
-         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
-          (e.g. WIN32 platforms)
-         * Cleanup header file inclusion for WIN32 platforms
-         * Cleanup code to avoid Microsoft Visual C++ compiler complaints
-         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
-           memory allocation routines
-         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
-         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
-           usage of 'assert' in non-WIN32 code
-         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
-           avoid infinite loop
-      * Always call 'fREe()' rather than 'free()'
-
-    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
-      * Fixed ordering problem with boundary-stamping
-
-    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
-      * Added pvalloc, as recommended by H.J. Liu
-      * Added 64bit pointer support mainly from Wolfram Gloger
-      * Added anonymously donated WIN32 sbrk emulation
-      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
-      * malloc_extend_top: fix mask error that caused wastage after
-        foreign sbrks
-      * Add linux mremap support code from HJ Liu
-
-    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
-      * Integrated most documentation with the code.
-      * Add support for mmap, with help from
-        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
-      * Use last_remainder in more cases.
-      * Pack bins using idea from  colin@nyx10.cs.du.edu
-      * Use ordered bins instead of best-fit threshhold
-      * Eliminate block-local decls to simplify tracing and debugging.
-      * Support another case of realloc via move into top
-      * Fix error occuring when initial sbrk_base not word-aligned.
-      * Rely on page size for units instead of SBRK_UNIT to
-        avoid surprises about sbrk alignment conventions.
-      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
-        (raymond@es.ele.tue.nl) for the suggestion.
-      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
-      * More precautions for cases where other routines call sbrk,
-        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
-      * Added macros etc., allowing use in linux libc from
-        H.J. Lu (hjl@gnu.ai.mit.edu)
-      * Inverted this history list
-
-    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
-      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
-      * Removed all preallocation code since under current scheme
-        the work required to undo bad preallocations exceeds
-        the work saved in good cases for most test programs.
-      * No longer use return list or unconsolidated bins since
-        no scheme using them consistently outperforms those that don't
-        given above changes.
-      * Use best fit for very large chunks to prevent some worst-cases.
-      * Added some support for debugging
-
-    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
-      * Removed footers when chunks are in use. Thanks to
-        Paul Wilson (wilson@cs.texas.edu) for the suggestion.
-
-    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
-      * Added malloc_trim, with help from Wolfram Gloger
-        (wmglo@Dent.MED.Uni-Muenchen.DE).
-
-    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
-
-    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
-      * realloc: try to expand in both directions
-      * malloc: swap order of clean-bin strategy;
-      * realloc: only conditionally expand backwards
-      * Try not to scavenge used bins
-      * Use bin counts as a guide to preallocation
-      * Occasionally bin return list chunks in first scan
-      * Add a few optimizations from colin@nyx10.cs.du.edu
-
-    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
-      * faster bin computation & slightly different binning
-      * merged all consolidations to one part of malloc proper
-         (eliminating old malloc_find_space & malloc_clean_bin)
-      * Scan 2 returns chunks (not just 1)
-      * Propagate failure in realloc if malloc returns 0
-      * Add stuff to allow compilation on non-ANSI compilers
-          from kpv@research.att.com
-
-    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
-      * removed potential for odd address access in prev_chunk
-      * removed dependency on getpagesize.h
-      * misc cosmetics and a bit more internal documentation
-      * anticosmetics: mangled names in macros to evade debugger strangeness
-      * tested on sparc, hp-700, dec-mips, rs6000
-          with gcc & native cc (hp, dec only) allowing
-          Detlefs & Zorn comparison study (in SIGPLAN Notices.)
-
-    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
-      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
-         structure of old version,  but most details differ.)
-
-*/
diff --git a/src/user/lib/vendor/dlmalloc/malloc.h b/src/user/lib/vendor/dlmalloc/malloc.h
deleted file mode 100644
index e52c9e5..0000000
--- a/src/user/lib/vendor/dlmalloc/malloc.h
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
-  Default header file for malloc-2.8.x, written by Doug Lea
-  and released to the public domain, as explained at
-  http://creativecommons.org/publicdomain/zero/1.0/ 
- 
-  This header is for ANSI C/C++ only.  You can set any of
-  the following #defines before including:
-
-  * If USE_DL_PREFIX is defined, it is assumed that malloc.c 
-    was also compiled with this option, so all routines
-    have names starting with "dl".
-
-  * If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
-    file will be #included AFTER <malloc.h>. This is needed only if
-    your system defines a struct mallinfo that is incompatible with the
-    standard one declared here.  Otherwise, you can include this file
-    INSTEAD of your system system <malloc.h>.  At least on ANSI, all
-    declarations should be compatible with system versions
-
-  * If MSPACES is defined, declarations for mspace versions are included.
-*/
-
-#ifndef MALLOC_280_H
-#define MALLOC_280_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h>   /* for size_t */
-
-#ifndef ONLY_MSPACES
-#define ONLY_MSPACES 0     /* define to a value */
-#elif ONLY_MSPACES != 0
-#define ONLY_MSPACES 1
-#endif  /* ONLY_MSPACES */
-#ifndef NO_MALLINFO
-#define NO_MALLINFO 0
-#endif  /* NO_MALLINFO */
-
-#ifndef MSPACES
-#if ONLY_MSPACES
-#define MSPACES 1
-#else   /* ONLY_MSPACES */
-#define MSPACES 0
-#endif  /* ONLY_MSPACES */
-#endif  /* MSPACES */
-
-#if !ONLY_MSPACES
-
-#ifndef USE_DL_PREFIX
-#define dlcalloc               calloc
-#define dlfree                 free
-#define dlmalloc               malloc
-#define dlmemalign             memalign
-#define dlposix_memalign       posix_memalign
-#define dlrealloc              realloc
-#define dlvalloc               valloc
-#define dlpvalloc              pvalloc
-#define dlmallinfo             mallinfo
-#define dlmallopt              mallopt
-#define dlmalloc_trim          malloc_trim
-#define dlmalloc_stats         malloc_stats
-#define dlmalloc_usable_size   malloc_usable_size
-#define dlmalloc_footprint     malloc_footprint
-#define dlmalloc_max_footprint malloc_max_footprint
-#define dlmalloc_footprint_limit malloc_footprint_limit
-#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
-#define dlmalloc_inspect_all   malloc_inspect_all
-#define dlindependent_calloc   independent_calloc
-#define dlindependent_comalloc independent_comalloc
-#define dlbulk_free            bulk_free
-#endif /* USE_DL_PREFIX */
-
-#if !NO_MALLINFO 
-#ifndef HAVE_USR_INCLUDE_MALLOC_H
-#ifndef _MALLOC_H
-#ifndef MALLINFO_FIELD_TYPE
-#define MALLINFO_FIELD_TYPE size_t
-#endif /* MALLINFO_FIELD_TYPE */
-#ifndef STRUCT_MALLINFO_DECLARED
-#define STRUCT_MALLINFO_DECLARED 1
-struct mallinfo {
-  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
-  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
-  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
-  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
-  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
-  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
-  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
-  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
-  MALLINFO_FIELD_TYPE fordblks; /* total free space */
-  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
-};
-#endif /* STRUCT_MALLINFO_DECLARED */
-#endif  /* _MALLOC_H */
-#endif  /* HAVE_USR_INCLUDE_MALLOC_H */
-#endif  /* !NO_MALLINFO */
-
-/*
-  malloc(size_t n)
-  Returns a pointer to a newly allocated chunk of at least n bytes, or
-  null if no space is available, in which case errno is set to ENOMEM
-  on ANSI C systems.
-
-  If n is zero, malloc returns a minimum-sized chunk. (The minimum
-  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
-  systems.)  Note that size_t is an unsigned type, so calls with
-  arguments that would be negative if signed are interpreted as
-  requests for huge amounts of space, which will often fail. The
-  maximum supported value of n differs across systems, but is in all
-  cases less than the maximum representable value of a size_t.
-*/
-void* dlmalloc(size_t);
-
-/*
-  free(void* p)
-  Releases the chunk of memory pointed to by p, that had been previously
-  allocated using malloc or a related routine such as realloc.
-  It has no effect if p is null. If p was not malloced or already
-  freed, free(p) will by default cuase the current program to abort.
-*/
-void  dlfree(void*);
-
-/*
-  calloc(size_t n_elements, size_t element_size);
-  Returns a pointer to n_elements * element_size bytes, with all locations
-  set to zero.
-*/
-void* dlcalloc(size_t, size_t);
-
-/*
-  realloc(void* p, size_t n)
-  Returns a pointer to a chunk of size n that contains the same data
-  as does chunk p up to the minimum of (n, p's size) bytes, or null
-  if no space is available.
-
-  The returned pointer may or may not be the same as p. The algorithm
-  prefers extending p in most cases when possible, otherwise it
-  employs the equivalent of a malloc-copy-free sequence.
-
-  If p is null, realloc is equivalent to malloc.
-
-  If space is not available, realloc returns null, errno is set (if on
-  ANSI) and p is NOT freed.
-
-  if n is for fewer bytes than already held by p, the newly unused
-  space is lopped off and freed if possible.  realloc with a size
-  argument of zero (re)allocates a minimum-sized chunk.
-
-  The old unix realloc convention of allowing the last-free'd chunk
-  to be used as an argument to realloc is not supported.
-*/
-void* dlrealloc(void*, size_t);
-
-/*
-  realloc_in_place(void* p, size_t n)
-  Resizes the space allocated for p to size n, only if this can be
-  done without moving p (i.e., only if there is adjacent space
-  available if n is greater than p's current allocated size, or n is
-  less than or equal to p's size). This may be used instead of plain
-  realloc if an alternative allocation strategy is needed upon failure
-  to expand space; for example, reallocation of a buffer that must be
-  memory-aligned or cleared. You can use realloc_in_place to trigger
-  these alternatives only when needed.
-
-  Returns p if successful; otherwise null.
-*/
-void* dlrealloc_in_place(void*, size_t);
-
-/*
-  memalign(size_t alignment, size_t n);
-  Returns a pointer to a newly allocated chunk of n bytes, aligned
-  in accord with the alignment argument.
-
-  The alignment argument should be a power of two. If the argument is
-  not a power of two, the nearest greater power is used.
-  8-byte alignment is guaranteed by normal malloc calls, so don't
-  bother calling memalign with an argument of 8 or less.
-
-  Overreliance on memalign is a sure way to fragment space.
-*/
-void* dlmemalign(size_t, size_t);
-
-/*
-  int posix_memalign(void** pp, size_t alignment, size_t n);
-  Allocates a chunk of n bytes, aligned in accord with the alignment
-  argument. Differs from memalign only in that it (1) assigns the
-  allocated memory to *pp rather than returning it, (2) fails and
-  returns EINVAL if the alignment is not a power of two (3) fails and
-  returns ENOMEM if memory cannot be allocated.
-*/
-int dlposix_memalign(void**, size_t, size_t);
-
-/*
-  valloc(size_t n);
-  Equivalent to memalign(pagesize, n), where pagesize is the page
-  size of the system. If the pagesize is unknown, 4096 is used.
-*/
-void* dlvalloc(size_t);
-
-/*
-  mallopt(int parameter_number, int parameter_value)
-  Sets tunable parameters The format is to provide a
-  (parameter-number, parameter-value) pair.  mallopt then sets the
-  corresponding parameter to the argument value if it can (i.e., so
-  long as the value is meaningful), and returns 1 if successful else
-  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,
-  normally defined in malloc.h.  None of these are use in this malloc,
-  so setting them has no effect. But this malloc also supports other
-  options in mallopt:
-
-  Symbol            param #  default    allowed param values
-  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1U disables trimming)
-  M_GRANULARITY        -2     page size   any power of 2 >= page size
-  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
-*/
-int dlmallopt(int, int);
-
-#define M_TRIM_THRESHOLD     (-1)
-#define M_GRANULARITY        (-2)
-#define M_MMAP_THRESHOLD     (-3)
-
-
-/*
-  malloc_footprint();
-  Returns the number of bytes obtained from the system.  The total
-  number of bytes allocated by malloc, realloc etc., is less than this
-  value. Unlike mallinfo, this function returns only a precomputed
-  result, so can be called frequently to monitor memory consumption.
-  Even if locks are otherwise defined, this function does not use them,
-  so results might not be up to date.
-*/
-size_t dlmalloc_footprint(void);
-
-/*
-  malloc_max_footprint();
-  Returns the maximum number of bytes obtained from the system. This
-  value will be greater than current footprint if deallocated space
-  has been reclaimed by the system. The peak number of bytes allocated
-  by malloc, realloc etc., is less than this value. Unlike mallinfo,
-  this function returns only a precomputed result, so can be called
-  frequently to monitor memory consumption.  Even if locks are
-  otherwise defined, this function does not use them, so results might
-  not be up to date.
-*/
-size_t dlmalloc_max_footprint(void);
-
-/*
-  malloc_footprint_limit();
-  Returns the number of bytes that the heap is allowed to obtain from
-  the system, returning the last value returned by
-  malloc_set_footprint_limit, or the maximum size_t value if
-  never set. The returned value reflects a permission. There is no
-  guarantee that this number of bytes can actually be obtained from
-  the system.  
-*/
-size_t dlmalloc_footprint_limit(void);
-
-/*
-  malloc_set_footprint_limit();
-  Sets the maximum number of bytes to obtain from the system, causing
-  failure returns from malloc and related functions upon attempts to
-  exceed this value. The argument value may be subject to page
-  rounding to an enforceable limit; this actual value is returned.
-  Using an argument of the maximum possible size_t effectively
-  disables checks. If the argument is less than or equal to the
-  current malloc_footprint, then all future allocations that require
-  additional system memory will fail. However, invocation cannot
-  retroactively deallocate existing used memory.
-*/
-size_t dlmalloc_set_footprint_limit(size_t bytes);
-
-/*
-  malloc_inspect_all(void(*handler)(void *start,
-                                    void *end,
-                                    size_t used_bytes,
-                                    void* callback_arg),
-                      void* arg);
-  Traverses the heap and calls the given handler for each managed
-  region, skipping all bytes that are (or may be) used for bookkeeping
-  purposes.  Traversal does not include include chunks that have been
-  directly memory mapped. Each reported region begins at the start
-  address, and continues up to but not including the end address.  The
-  first used_bytes of the region contain allocated data. If
-  used_bytes is zero, the region is unallocated. The handler is
-  invoked with the given callback argument. If locks are defined, they
-  are held during the entire traversal. It is a bad idea to invoke
-  other malloc functions from within the handler.
-
-  For example, to count the number of in-use chunks with size greater
-  than 1000, you could write:
-  static int count = 0;
-  void count_chunks(void* start, void* end, size_t used, void* arg) {
-    if (used >= 1000) ++count;
-  }
-  then:
-    malloc_inspect_all(count_chunks, NULL);
-
-  malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
-*/
-void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
-                           void* arg);
-
-#if !NO_MALLINFO
-/*
-  mallinfo()
-  Returns (by copy) a struct containing various summary statistics:
-
-  arena:     current total non-mmapped bytes allocated from system
-  ordblks:   the number of free chunks
-  smblks:    always zero.
-  hblks:     current number of mmapped regions
-  hblkhd:    total bytes held in mmapped regions
-  usmblks:   the maximum total allocated space. This will be greater
-                than current total if trimming has occurred.
-  fsmblks:   always zero
-  uordblks:  current total allocated space (normal or mmapped)
-  fordblks:  total free space
-  keepcost:  the maximum number of bytes that could ideally be released
-               back to system via malloc_trim. ("ideally" means that
-               it ignores page restrictions etc.)
-
-  Because these fields are ints, but internal bookkeeping may
-  be kept as longs, the reported values may wrap around zero and
-  thus be inaccurate.
-*/
-
-struct mallinfo dlmallinfo(void);
-#endif  /* NO_MALLINFO */
-
-/*
-  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
-
-  independent_calloc is similar to calloc, but instead of returning a
-  single cleared space, it returns an array of pointers to n_elements
-  independent elements that can hold contents of size elem_size, each
-  of which starts out cleared, and can be independently freed,
-  realloc'ed etc. The elements are guaranteed to be adjacently
-  allocated (this is not guaranteed to occur with multiple callocs or
-  mallocs), which may also improve cache locality in some
-  applications.
-
-  The "chunks" argument is optional (i.e., may be null, which is
-  probably the most typical usage). If it is null, the returned array
-  is itself dynamically allocated and should also be freed when it is
-  no longer needed. Otherwise, the chunks array must be of at least
-  n_elements in length. It is filled in with the pointers to the
-  chunks.
-
-  In either case, independent_calloc returns this pointer array, or
-  null if the allocation failed.  If n_elements is zero and "chunks"
-  is null, it returns a chunk representing an array with zero elements
-  (which should be freed if not wanted).
-
-  Each element must be freed when it is no longer needed. This can be
-  done all at once using bulk_free.
-
-  independent_calloc simplifies and speeds up implementations of many
-  kinds of pools.  It may also be useful when constructing large data
-  structures that initially have a fixed number of fixed-sized nodes,
-  but the number is not known at compile time, and some of the nodes
-  may later need to be freed. For example:
-
-  struct Node { int item; struct Node* next; };
-
-  struct Node* build_list() {
-    struct Node** pool;
-    int n = read_number_of_nodes_needed();
-    if (n <= 0) return 0;
-    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
-    if (pool == 0) die();
-    // organize into a linked list...
-    struct Node* first = pool[0];
-    for (i = 0; i < n-1; ++i)
-      pool[i]->next = pool[i+1];
-    free(pool);     // Can now free the array (or not, if it is needed later)
-    return first;
-  }
-*/
-void** dlindependent_calloc(size_t, size_t, void**);
-
-/*
-  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
-
-  independent_comalloc allocates, all at once, a set of n_elements
-  chunks with sizes indicated in the "sizes" array.    It returns
-  an array of pointers to these elements, each of which can be
-  independently freed, realloc'ed etc. The elements are guaranteed to
-  be adjacently allocated (this is not guaranteed to occur with
-  multiple callocs or mallocs), which may also improve cache locality
-  in some applications.
-
-  The "chunks" argument is optional (i.e., may be null). If it is null
-  the returned array is itself dynamically allocated and should also
-  be freed when it is no longer needed. Otherwise, the chunks array
-  must be of at least n_elements in length. It is filled in with the
-  pointers to the chunks.
-
-  In either case, independent_comalloc returns this pointer array, or
-  null if the allocation failed.  If n_elements is zero and chunks is
-  null, it returns a chunk representing an array with zero elements
-  (which should be freed if not wanted).
-
-  Each element must be freed when it is no longer needed. This can be
-  done all at once using bulk_free.
-
-  independent_comallac differs from independent_calloc in that each
-  element may have a different size, and also that it does not
-  automatically clear elements.
-
-  independent_comalloc can be used to speed up allocation in cases
-  where several structs or objects must always be allocated at the
-  same time.  For example:
-
-  struct Head { ... }
-  struct Foot { ... }
-
-  void send_message(char* msg) {
-    int msglen = strlen(msg);
-    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
-    void* chunks[3];
-    if (independent_comalloc(3, sizes, chunks) == 0)
-      die();
-    struct Head* head = (struct Head*)(chunks[0]);
-    char*        body = (char*)(chunks[1]);
-    struct Foot* foot = (struct Foot*)(chunks[2]);
-    // ...
-  }
-
-  In general though, independent_comalloc is worth using only for
-  larger values of n_elements. For small values, you probably won't
-  detect enough difference from series of malloc calls to bother.
-
-  Overuse of independent_comalloc can increase overall memory usage,
-  since it cannot reuse existing noncontiguous small chunks that
-  might be available for some of the elements.
-*/
-void** dlindependent_comalloc(size_t, size_t*, void**);
-
-/*
-  bulk_free(void* array[], size_t n_elements)
-  Frees and clears (sets to null) each non-null pointer in the given
-  array.  This is likely to be faster than freeing them one-by-one.
-  If footers are used, pointers that have been allocated in different
-  mspaces are not freed or cleared, and the count of all such pointers
-  is returned.  For large arrays of pointers with poor locality, it
-  may be worthwhile to sort this array before calling bulk_free.
-*/
-size_t  dlbulk_free(void**, size_t n_elements);
-
-/*
-  pvalloc(size_t n);
-  Equivalent to valloc(minimum-page-that-holds(n)), that is,
-  round up n to nearest pagesize.
- */
-void*  dlpvalloc(size_t);
-
-/*
-  malloc_trim(size_t pad);
-
-  If possible, gives memory back to the system (via negative arguments
-  to sbrk) if there is unused memory at the `high' end of the malloc
-  pool or in unused MMAP segments. You can call this after freeing
-  large blocks of memory to potentially reduce the system-level memory
-  requirements of a program. However, it cannot guarantee to reduce
-  memory. Under some allocation patterns, some large free blocks of
-  memory will be locked between two used chunks, so they cannot be
-  given back to the system.
-
-  The `pad' argument to malloc_trim represents the amount of free
-  trailing space to leave untrimmed. If this argument is zero, only
-  the minimum amount of memory to maintain internal data structures
-  will be left. Non-zero arguments can be supplied to maintain enough
-  trailing space to service future expected allocations without having
-  to re-obtain memory from the system.
-
-  Malloc_trim returns 1 if it actually released any memory, else 0.
-*/
-int  dlmalloc_trim(size_t);
-
-/*
-  malloc_stats();
-  Prints on stderr the amount of space obtained from the system (both
-  via sbrk and mmap), the maximum amount (which may be more than
-  current if malloc_trim and/or munmap got called), and the current
-  number of bytes allocated via malloc (or realloc, etc) but not yet
-  freed. Note that this is the number of bytes allocated, not the
-  number requested. It will be larger than the number requested
-  because of alignment and bookkeeping overhead. Because it includes
-  alignment wastage as being in use, this figure may be greater than
-  zero even when no user-level chunks are allocated.
-
-  The reported current and maximum system memory can be inaccurate if
-  a program makes other calls to system memory allocation functions
-  (normally sbrk) outside of malloc.
-
-  malloc_stats prints only the most commonly interesting statistics.
-  More information can be obtained by calling mallinfo.
-  
-  malloc_stats is not compiled if NO_MALLOC_STATS is defined.
-*/
-void  dlmalloc_stats(void);
-
-#endif /* !ONLY_MSPACES */
-
-/*
-  malloc_usable_size(void* p);
-
-  Returns the number of bytes you can actually use in
-  an allocated chunk, which may be more than you requested (although
-  often not) due to alignment and minimum size constraints.
-  You can use this many bytes without worrying about
-  overwriting other allocated objects. This is not a particularly great
-  programming practice. malloc_usable_size can be more useful in
-  debugging and assertions, for example:
-
-  p = malloc(n);
-  assert(malloc_usable_size(p) >= 256);
-*/
-size_t dlmalloc_usable_size(const void*);
-
-#if MSPACES
-
-/*
-  mspace is an opaque type representing an independent
-  region of space that supports mspace_malloc, etc.
-*/
-typedef void* mspace;
-
-/*
-  create_mspace creates and returns a new independent space with the
-  given initial capacity, or, if 0, the default granularity size.  It
-  returns null if there is no system memory available to create the
-  space.  If argument locked is non-zero, the space uses a separate
-  lock to control access. The capacity of the space will grow
-  dynamically as needed to service mspace_malloc requests.  You can
-  control the sizes of incremental increases of this space by
-  compiling with a different DEFAULT_GRANULARITY or dynamically
-  setting with mallopt(M_GRANULARITY, value).
-*/
-mspace create_mspace(size_t capacity, int locked);
-
-/*
-  destroy_mspace destroys the given space, and attempts to return all
-  of its memory back to the system, returning the total number of
-  bytes freed. After destruction, the results of access to all memory
-  used by the space become undefined.
-*/
-size_t destroy_mspace(mspace msp);
-
-/*
-  create_mspace_with_base uses the memory supplied as the initial base
-  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
-  space is used for bookkeeping, so the capacity must be at least this
-  large. (Otherwise 0 is returned.) When this initial space is
-  exhausted, additional memory will be obtained from the system.
-  Destroying this space will deallocate all additionally allocated
-  space (if possible) but not the initial base.
-*/
-mspace create_mspace_with_base(void* base, size_t capacity, int locked);
-
-/*
-  mspace_track_large_chunks controls whether requests for large chunks
-  are allocated in their own untracked mmapped regions, separate from
-  others in this mspace. By default large chunks are not tracked,
-  which reduces fragmentation. However, such chunks are not
-  necessarily released to the system upon destroy_mspace.  Enabling
-  tracking by setting to true may increase fragmentation, but avoids
-  leakage when relying on destroy_mspace to release all memory
-  allocated using this space.  The function returns the previous
-  setting.
-*/
-int mspace_track_large_chunks(mspace msp, int enable);
-
-#if !NO_MALLINFO
-/*
-  mspace_mallinfo behaves as mallinfo, but reports properties of
-  the given space.
-*/
-struct mallinfo mspace_mallinfo(mspace msp);
-#endif /* NO_MALLINFO */
-
-/*
-  An alias for mallopt.
-*/
-int mspace_mallopt(int, int);
-
-/*
-  The following operate identically to their malloc counterparts
-  but operate only for the given mspace argument
-*/
-void* mspace_malloc(mspace msp, size_t bytes);
-void mspace_free(mspace msp, void* mem);
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
-void* mspace_realloc(mspace msp, void* mem, size_t newsize);
-void* mspace_realloc_in_place(mspace msp, void* mem, size_t newsize);
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
-void** mspace_independent_calloc(mspace msp, size_t n_elements,
-                                 size_t elem_size, void* chunks[]);
-void** mspace_independent_comalloc(mspace msp, size_t n_elements,
-                                   size_t sizes[], void* chunks[]);
-size_t mspace_bulk_free(mspace msp, void**, size_t n_elements);
-size_t mspace_usable_size(const void* mem);
-void mspace_malloc_stats(mspace msp);
-int mspace_trim(mspace msp, size_t pad);
-size_t mspace_footprint(mspace msp);
-size_t mspace_max_footprint(mspace msp);
-size_t mspace_footprint_limit(mspace msp);
-size_t mspace_set_footprint_limit(mspace msp, size_t bytes);
-void mspace_inspect_all(mspace msp, 
-                        void(*handler)(void *, void *, size_t, void*),
-                        void* arg);
-#endif  /* MSPACES */
-
-#ifdef __cplusplus
-};  /* end of extern "C" */
-#endif
-
-#endif /* MALLOC_280_H */
diff --git a/src/user/lib/vendor/getopt/getopt.c b/src/user/lib/vendor/getopt/getopt.c
deleted file mode 100644
index 63c9b51..0000000
--- a/src/user/lib/vendor/getopt/getopt.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Adapted from https://github.com/skeeto/getopt by Chris Wellons */
-
-/* A minimal POSIX getopt() implementation in ANSI C
- *
- * This is free and unencumbered software released into the public domain.
- *
- * This implementation supports the convention of resetting the option
- * parser by assigning optind to 0. This resets the internal state
- * appropriately.
- *
- * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
- */
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include "getopt.h"
-
-int optind;
-int opterr = 1;
-int optopt;
-char *optarg;
-
-int
-getopt(int argc, char * const argv[], const char *optstring)
-{
-	static int optpos = 1;
-	const char *arg;
-
-	/* Reset? */
-	if (optind == 0) {
-		optind = !!argc;
-		optpos = 1;
-	}
-
-	arg = argv[optind];
-	if (arg && strcmp(arg, "--") == 0) {
-		optind++;
-		return -1;
-	} else if (!arg || arg[0] != '-' || !isalnum(arg[1])) {
-		return -1;
-	} else {
-		const char *opt = strchr(optstring, arg[optpos]);
-		optopt = arg[optpos];
-		if (!opt) {
-			if (opterr && *optstring != ':')
-				fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt);
-			return '?';
-		} else if (opt[1] == ':') {
-			if (arg[optpos + 1]) {
-				optarg = (char *)arg + optpos + 1;
-				optind++;
-				optpos = 1;
-				return optopt;
-			} else if (argv[optind + 1]) {
-				optarg = (char *)argv[optind + 1];
-				optind += 2;
-				optpos = 1;
-				return optopt;
-			} else {
-				if (opterr && *optstring != ':')
-					fprintf(stderr,
-					        "%s: option requires an argument: %c\n",
-					        argv[0], optopt);
-				return *optstring == ':' ? ':' : '?';
-			}
-		} else {
-			if (!arg[++optpos]) {
-				optind++;
-				optpos = 1;
-			}
-			return optopt;
-		}
-	}
-}
-
diff --git a/src/user/lib/vendor/getopt/getopt.h b/src/user/lib/vendor/getopt/getopt.h
deleted file mode 100644
index 4cb075c..0000000
--- a/src/user/lib/vendor/getopt/getopt.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Adapted from https://github.com/skeeto/getopt by Chris Wellons */
-
-/* A minimal POSIX getopt() implementation in ANSI C
- *
- * This is free and unencumbered software released into the public domain.
- *
- * This implementation supports the convention of resetting the option
- * parser by assigning optind to 0. This resets the internal state
- * appropriately.
- *
- * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
- */
-#ifndef GETOPT_H
-#define GETOPT_H
-
-extern int optind, opterr, optopt;
-extern char *optarg;
-
-int getopt(int argc, char * const argv[], const char *optstring);
-
-#endif
-- 
cgit v1.2.3