Browse Source

PAGE_SIZE is not a valid symbol to use in that way. In particular,

on sparc, it expands to something that just plain does not work,
because the page size can be variable.  Sorry we didn't spot this
before.  Backing it all out to allow sparc to build; please find a
different way to fix it.
OPENBSD_4_5
deraadt 16 years ago
parent
commit
69d34d79a8
1 changed files with 164 additions and 235 deletions
  1. +164
    -235
      src/lib/libc/stdlib/malloc.c

+ 164
- 235
src/lib/libc/stdlib/malloc.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: malloc.c,v 1.113 2008/12/30 07:44:51 djm Exp $ */
/* $OpenBSD: malloc.c,v 1.114 2008/12/31 05:21:46 deraadt Exp $ */
/* /*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
* *
@ -125,7 +125,7 @@ struct dir_info {
#endif /* MALLOC_STATS */ #endif /* MALLOC_STATS */
u_int32_t canary2; u_int32_t canary2;
}; };
#define DIR_INFO_RSZ ((sizeof(struct dir_info) + PAGE_MASK) & ~PAGE_MASK)
/* /*
* This structure describes a page worth of chunks. * This structure describes a page worth of chunks.
@ -145,40 +145,29 @@ struct chunk_info {
u_long bits[(MALLOC_PAGESIZE / MALLOC_MINSIZE) / MALLOC_BITS]; u_long bits[(MALLOC_PAGESIZE / MALLOC_MINSIZE) / MALLOC_BITS];
}; };
struct malloc_readonly {
struct dir_info *g_pool; /* Main bookkeeping information */
int malloc_abort; /* abort() on error */
int malloc_freeprot; /* mprotect free pages PROT_NONE? */
int malloc_hint; /* call madvice on free pages? */
int malloc_junk; /* junk fill? */
int malloc_move; /* move allocations to end of page? */
int malloc_realloc; /* always realloc? */
int malloc_xmalloc; /* xmalloc behaviour? */
int malloc_zero; /* zero fill? */
size_t malloc_guard; /* use guard pages after allocations? */
u_int malloc_cache; /* free pages we cache */
#ifdef MALLOC_STATS
int malloc_stats; /* dump statistics at end */
#endif
u_int32_t malloc_canary; /* Matched against ones in g_pool */
};
/* This object is mapped PROT_READ after initialisation to prevent tampering */
static union {
struct malloc_readonly mopts;
u_char _pad[PAGE_SIZE];
} malloc_readonly __attribute__((aligned(PAGE_SIZE)));
#define mopts malloc_readonly.mopts
#define g_pool mopts.g_pool
static struct dir_info g_pool;
static char *malloc_func; /* current function */
char *malloc_options; /* compile-time options */ char *malloc_options; /* compile-time options */
static char *malloc_func; /* current function */
static int malloc_abort = 1; /* abort() on error */
static int malloc_active; /* status of malloc */ static int malloc_active; /* status of malloc */
static int malloc_freeprot; /* mprotect free pages PROT_NONE? */
static int malloc_hint; /* call madvice on free pages? */
static int malloc_junk; /* junk fill? */
static int malloc_move = 1; /* move allocations to end of page? */
static int malloc_realloc; /* always realloc? */
static int malloc_xmalloc; /* xmalloc behaviour? */
static int malloc_zero; /* zero fill? */
static size_t malloc_guard; /* use guard pages after allocations? */
static u_int malloc_cache = 64; /* free pages we cache */
static size_t malloc_guarded; /* bytes used for guards */ static size_t malloc_guarded; /* bytes used for guards */
static size_t malloc_used; /* bytes allocated */ static size_t malloc_used; /* bytes allocated */
#ifdef MALLOC_STATS
static int malloc_stats; /* dump statistics at end */
#endif
static size_t rbytesused; /* random bytes used */ static size_t rbytesused; /* random bytes used */
static u_char rbytes[512]; /* random bytes */ static u_char rbytes[512]; /* random bytes */
static u_char getrbyte(void); static u_char getrbyte(void);
@ -258,7 +247,7 @@ dump_free_page_info(int fd, struct dir_info *d)
snprintf(buf, sizeof(buf), "Free pages cached: %zu\n", snprintf(buf, sizeof(buf), "Free pages cached: %zu\n",
d->free_regions_size); d->free_regions_size);
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
for (i = 0; i < mopts.malloc_cache; i++) {
for (i = 0; i < malloc_cache; i++) {
if (d->free_regions[i].p != NULL) { if (d->free_regions[i].p != NULL) {
snprintf(buf, sizeof(buf), "%2d) ", i); snprintf(buf, sizeof(buf), "%2d) ", i);
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
@ -277,8 +266,6 @@ malloc_dump1(int fd, struct dir_info *d)
snprintf(buf, sizeof(buf), "Malloc dir of %s at %p\n", __progname, d); snprintf(buf, sizeof(buf), "Malloc dir of %s at %p\n", __progname, d);
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
if (d == NULL)
return;
snprintf(buf, sizeof(buf), "Regions slots %zu\n", d->regions_total); snprintf(buf, sizeof(buf), "Regions slots %zu\n", d->regions_total);
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Finds %zu/%zu %f\n", d->finds, snprintf(buf, sizeof(buf), "Finds %zu/%zu %f\n", d->finds,
@ -326,7 +313,7 @@ malloc_dump1(int fd, struct dir_info *d)
void void
malloc_dump(int fd) malloc_dump(int fd)
{ {
malloc_dump1(fd, g_pool);
malloc_dump1(fd, &g_pool);
} }
static void static void
@ -366,11 +353,11 @@ wrterror(char *p)
writev(STDERR_FILENO, iov, 5); writev(STDERR_FILENO, iov, 5);
#ifdef MALLOC_STATS #ifdef MALLOC_STATS
if (mopts.malloc_stats)
if (malloc_stats)
malloc_dump(STDERR_FILENO); malloc_dump(STDERR_FILENO);
#endif /* MALLOC_STATS */ #endif /* MALLOC_STATS */
//malloc_active--; //malloc_active--;
if (mopts.malloc_abort)
if (malloc_abort)
abort(); abort();
} }
@ -394,19 +381,19 @@ unmap(struct dir_info *d, void *p, size_t sz)
return; return;
} }
if (psz > mopts.malloc_cache) {
if (psz > malloc_cache) {
if (munmap(p, sz)) if (munmap(p, sz))
wrterror("munmap"); wrterror("munmap");
malloc_used -= sz; malloc_used -= sz;
return; return;
} }
tounmap = 0; tounmap = 0;
rsz = mopts.malloc_cache - d->free_regions_size;
rsz = malloc_cache - d->free_regions_size;
if (psz > rsz) if (psz > rsz)
tounmap = psz - rsz; tounmap = psz - rsz;
offset = getrbyte(); offset = getrbyte();
for (i = 0; tounmap > 0 && i < mopts.malloc_cache; i++) {
r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)];
for (i = 0; tounmap > 0 && i < malloc_cache; i++) {
r = &d->free_regions[(i + offset) & (malloc_cache - 1)];
if (r->p != NULL) { if (r->p != NULL) {
rsz = r->size << MALLOC_PAGESHIFT; rsz = r->size << MALLOC_PAGESHIFT;
if (munmap(r->p, rsz)) if (munmap(r->p, rsz))
@ -423,12 +410,12 @@ unmap(struct dir_info *d, void *p, size_t sz)
} }
if (tounmap > 0) if (tounmap > 0)
wrterror("malloc cache underflow"); wrterror("malloc cache underflow");
for (i = 0; i < mopts.malloc_cache; i++) {
for (i = 0; i < malloc_cache; i++) {
r = &d->free_regions[i]; r = &d->free_regions[i];
if (r->p == NULL) { if (r->p == NULL) {
if (mopts.malloc_hint)
if (malloc_hint)
madvise(p, sz, MADV_FREE); madvise(p, sz, MADV_FREE);
if (mopts.malloc_freeprot)
if (malloc_freeprot)
mprotect(p, sz, PROT_NONE); mprotect(p, sz, PROT_NONE);
r->p = p; r->p = p;
r->size = psz; r->size = psz;
@ -436,9 +423,9 @@ unmap(struct dir_info *d, void *p, size_t sz)
break; break;
} }
} }
if (i == mopts.malloc_cache)
if (i == malloc_cache)
wrterror("malloc free slot lost"); wrterror("malloc free slot lost");
if (d->free_regions_size > mopts.malloc_cache)
if (d->free_regions_size > malloc_cache)
wrterror("malloc cache overflow"); wrterror("malloc cache overflow");
} }
@ -449,7 +436,7 @@ zapcacheregion(struct dir_info *d, void *p)
struct region_info *r; struct region_info *r;
size_t rsz; size_t rsz;
for (i = 0; i < mopts.malloc_cache; i++) {
for (i = 0; i < malloc_cache; i++) {
r = &d->free_regions[i]; r = &d->free_regions[i];
if (r->p == p) { if (r->p == p) {
rsz = r->size << MALLOC_PAGESHIFT; rsz = r->size << MALLOC_PAGESHIFT;
@ -471,9 +458,6 @@ map(struct dir_info *d, size_t sz, int zero_fill)
u_int i, offset; u_int i, offset;
void *p; void *p;
if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)d) ||
d->canary1 != ~d->canary2)
wrterror("internal struct corrupt");
if (sz != PAGEROUND(sz)) { if (sz != PAGEROUND(sz)) {
wrterror("map round"); wrterror("map round");
return NULL; return NULL;
@ -486,22 +470,21 @@ map(struct dir_info *d, size_t sz, int zero_fill)
return p; return p;
} }
offset = getrbyte(); offset = getrbyte();
for (i = 0; i < mopts.malloc_cache; i++) {
r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)];
for (i = 0; i < malloc_cache; i++) {
r = &d->free_regions[(i + offset) & (malloc_cache - 1)];
if (r->p != NULL) { if (r->p != NULL) {
if (r->size == psz) { if (r->size == psz) {
p = r->p; p = r->p;
if (mopts.malloc_freeprot)
if (malloc_freeprot)
mprotect(p, sz, PROT_READ | PROT_WRITE); mprotect(p, sz, PROT_READ | PROT_WRITE);
if (mopts.malloc_hint)
if (malloc_hint)
madvise(p, sz, MADV_NORMAL); madvise(p, sz, MADV_NORMAL);
r->p = NULL; r->p = NULL;
r->size = 0; r->size = 0;
d->free_regions_size -= psz; d->free_regions_size -= psz;
if (zero_fill) if (zero_fill)
memset(p, 0, sz); memset(p, 0, sz);
else if (mopts.malloc_junk &&
mopts.malloc_freeprot)
else if (malloc_junk && malloc_freeprot)
memset(p, SOME_FREEJUNK, sz); memset(p, SOME_FREEJUNK, sz);
return p; return p;
} else if (r->size > psz) } else if (r->size > psz)
@ -511,9 +494,9 @@ map(struct dir_info *d, size_t sz, int zero_fill)
if (big != NULL) { if (big != NULL) {
r = big; r = big;
p = (char *)r->p + ((r->size - psz) << MALLOC_PAGESHIFT); p = (char *)r->p + ((r->size - psz) << MALLOC_PAGESHIFT);
if (mopts.malloc_freeprot)
if (malloc_freeprot)
mprotect(p, sz, PROT_READ | PROT_WRITE); mprotect(p, sz, PROT_READ | PROT_WRITE);
if (mopts.malloc_hint)
if (malloc_hint)
madvise(p, sz, MADV_NORMAL); madvise(p, sz, MADV_NORMAL);
r->size -= psz; r->size -= psz;
d->free_regions_size -= psz; d->free_regions_size -= psz;
@ -524,7 +507,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
p = MMAP(sz); p = MMAP(sz);
if (p != MAP_FAILED) if (p != MAP_FAILED)
malloc_used += sz; malloc_used += sz;
if (d->free_regions_size > mopts.malloc_cache)
if (d->free_regions_size > malloc_cache)
wrterror("malloc cache"); wrterror("malloc cache");
/* zero fill not needed */ /* zero fill not needed */
return p; return p;
@ -549,22 +532,14 @@ getrbyte(void)
* Initialize a dir_info, which should have been cleared by caller * Initialize a dir_info, which should have been cleared by caller
*/ */
static int static int
omalloc_init(struct dir_info **dp)
omalloc_init(struct dir_info *d)
{ {
char *p, b[64]; char *p, b[64];
int i, j; int i, j;
size_t d_avail, regioninfo_size;
struct dir_info *d;
size_t regioninfo_size;
rbytes_init(); rbytes_init();
/*
* Default options
*/
mopts.malloc_abort = 1;
mopts.malloc_move = 1;
mopts.malloc_cache = 64;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
switch (i) { switch (i) {
case 0: case 0:
@ -590,77 +565,77 @@ omalloc_init(struct dir_info **dp)
for (; p != NULL && *p != '\0'; p++) { for (; p != NULL && *p != '\0'; p++) {
switch (*p) { switch (*p) {
case '>': case '>':
mopts.malloc_cache <<= 1;
if (mopts.malloc_cache > MALLOC_MAXCACHE)
mopts.malloc_cache = MALLOC_MAXCACHE;
malloc_cache <<= 1;
if (malloc_cache > MALLOC_MAXCACHE)
malloc_cache = MALLOC_MAXCACHE;
break; break;
case '<': case '<':
mopts.malloc_cache >>= 1;
malloc_cache >>= 1;
break; break;
case 'a': case 'a':
mopts.malloc_abort = 0;
malloc_abort = 0;
break; break;
case 'A': case 'A':
mopts.malloc_abort = 1;
malloc_abort = 1;
break; break;
#ifdef MALLOC_STATS #ifdef MALLOC_STATS
case 'd': case 'd':
mopts.malloc_stats = 0;
malloc_stats = 0;
break; break;
case 'D': case 'D':
mopts.malloc_stats = 1;
malloc_stats = 1;
break; break;
#endif /* MALLOC_STATS */ #endif /* MALLOC_STATS */
case 'f': case 'f':
mopts.malloc_freeprot = 0;
malloc_freeprot = 0;
break; break;
case 'F': case 'F':
mopts.malloc_freeprot = 1;
malloc_freeprot = 1;
break; break;
case 'g': case 'g':
mopts.malloc_guard = 0;
malloc_guard = 0;
break; break;
case 'G': case 'G':
mopts.malloc_guard = MALLOC_PAGESIZE;
malloc_guard = MALLOC_PAGESIZE;
break; break;
case 'h': case 'h':
mopts.malloc_hint = 0;
malloc_hint = 0;
break; break;
case 'H': case 'H':
mopts.malloc_hint = 1;
malloc_hint = 1;
break; break;
case 'j': case 'j':
mopts.malloc_junk = 0;
malloc_junk = 0;
break; break;
case 'J': case 'J':
mopts.malloc_junk = 1;
malloc_junk = 1;
break; break;
case 'n': case 'n':
case 'N': case 'N':
break; break;
case 'p': case 'p':
mopts.malloc_move = 0;
malloc_move = 0;
break; break;
case 'P': case 'P':
mopts.malloc_move = 1;
malloc_move = 1;
break; break;
case 'r': case 'r':
mopts.malloc_realloc = 0;
malloc_realloc = 0;
break; break;
case 'R': case 'R':
mopts.malloc_realloc = 1;
malloc_realloc = 1;
break; break;
case 'x': case 'x':
mopts.malloc_xmalloc = 0;
malloc_xmalloc = 0;
break; break;
case 'X': case 'X':
mopts.malloc_xmalloc = 1;
malloc_xmalloc = 1;
break; break;
case 'z': case 'z':
mopts.malloc_zero = 0;
malloc_zero = 0;
break; break;
case 'Z': case 'Z':
mopts.malloc_zero = 1;
malloc_zero = 1;
break; break;
default: { default: {
static const char q[] = "malloc() warning: " static const char q[] = "malloc() warning: "
@ -676,33 +651,17 @@ omalloc_init(struct dir_info **dp)
* We want junk in the entire allocation, and zero only in the part * We want junk in the entire allocation, and zero only in the part
* the user asked for. * the user asked for.
*/ */
if (mopts.malloc_zero)
mopts.malloc_junk = 1;
if (malloc_zero)
malloc_junk = 1;
#ifdef MALLOC_STATS #ifdef MALLOC_STATS
if (mopts.malloc_stats && (atexit(malloc_exit) == -1)) {
if (malloc_stats && (atexit(malloc_exit) == -1)) {
static const char q[] = "malloc() warning: atexit(2) failed." static const char q[] = "malloc() warning: atexit(2) failed."
" Will not be able to dump stats on exit\n"; " Will not be able to dump stats on exit\n";
write(STDERR_FILENO, q, sizeof(q) - 1); write(STDERR_FILENO, q, sizeof(q) - 1);
} }
#endif /* MALLOC_STATS */ #endif /* MALLOC_STATS */
while ((mopts.malloc_canary = arc4random()) == 0)
;
/*
* Allocate dir_info with a guard page on either side. Also
* randomise offset inside the page at which the dir_info
* lies (subject to alignment by 1 << MALLOC_MINSHIFT)
*/
if ((p = MMAP(PAGE_SIZE + DIR_INFO_RSZ + PAGE_SIZE)) == NULL)
return -1;
mprotect(p, PAGE_SIZE, PROT_NONE);
mprotect(p + PAGE_SIZE + DIR_INFO_RSZ, PAGE_SIZE, PROT_NONE);
d_avail = (DIR_INFO_RSZ - sizeof(*d)) >> MALLOC_MINSHIFT;
d = (struct dir_info *)(p + PAGE_SIZE +
(arc4random_uniform(d_avail) << MALLOC_MINSHIFT));
d->regions_bits = 9; d->regions_bits = 9;
d->regions_free = d->regions_total = 1 << d->regions_bits; d->regions_free = d->regions_total = 1 << d->regions_bits;
regioninfo_size = d->regions_total * sizeof(struct region_info); regioninfo_size = d->regions_total * sizeof(struct region_info);
@ -714,18 +673,8 @@ omalloc_init(struct dir_info **dp)
} }
malloc_used += regioninfo_size; malloc_used += regioninfo_size;
memset(d->r, 0, regioninfo_size); memset(d->r, 0, regioninfo_size);
d->canary1 = mopts.malloc_canary ^ (u_int32_t)d;
d->canary1 = arc4random();
d->canary2 = ~d->canary1; d->canary2 = ~d->canary1;
*dp = d;
/*
* Options have been set and will never be reset.
* Prevent further tampering with them.
*/
if (((uintptr_t)&malloc_readonly & PAGE_MASK) == 0)
mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ);
return 0; return 0;
} }
@ -843,8 +792,7 @@ find(struct dir_info *d, void *p)
size_t mask = d->regions_total - 1; size_t mask = d->regions_total - 1;
void *q, *r; void *q, *r;
if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)d) ||
d->canary1 != ~d->canary2)
if (d->canary1 != ~d->canary2)
wrterror("internal struct corrupt"); wrterror("internal struct corrupt");
p = MASK_POINTER(p); p = MASK_POINTER(p);
index = hash(p) & mask; index = hash(p) & mask;
@ -870,7 +818,7 @@ delete(struct dir_info *d, struct region_info *ri)
if (d->regions_total & (d->regions_total - 1)) if (d->regions_total & (d->regions_total - 1))
wrterror("regions_total not 2^x"); wrterror("regions_total not 2^x");
d->regions_free++; d->regions_free++;
STATS_INC(g_pool->deletes);
STATS_INC(g_pool.deletes);
i = ri - d->r; i = ri - d->r;
for (;;) { for (;;) {
@ -886,7 +834,7 @@ delete(struct dir_info *d, struct region_info *ri)
(j < i && i <= r)) (j < i && i <= r))
continue; continue;
d->r[j] = d->r[i]; d->r[j] = d->r[i];
STATS_INC(g_pool->delete_moves);
STATS_INC(g_pool.delete_moves);
break; break;
} }
@ -971,9 +919,6 @@ malloc_bytes(struct dir_info *d, size_t size)
u_long u, *lp; u_long u, *lp;
struct chunk_info *bp; struct chunk_info *bp;
if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)d) ||
d->canary1 != ~d->canary2)
wrterror("internal struct corrupt");
/* Don't bother with anything less than this */ /* Don't bother with anything less than this */
/* unless we have a malloc(0) requests */ /* unless we have a malloc(0) requests */
if (size != 0 && size < MALLOC_MINSIZE) if (size != 0 && size < MALLOC_MINSIZE)
@ -1038,7 +983,7 @@ malloc_bytes(struct dir_info *d, size_t size)
k += (lp - bp->bits) * MALLOC_BITS; k += (lp - bp->bits) * MALLOC_BITS;
k <<= bp->shift; k <<= bp->shift;
if (mopts.malloc_junk && bp->size > 0)
if (malloc_junk && bp->size > 0)
memset((char *)bp->page + k, SOME_JUNK, bp->size); memset((char *)bp->page + k, SOME_JUNK, bp->size);
return ((char *)bp->page + k); return ((char *)bp->page + k);
} }
@ -1102,7 +1047,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
} }
*mp = info->next; *mp = info->next;
if (info->size == 0 && !mopts.malloc_freeprot)
if (info->size == 0 && !malloc_freeprot)
mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE); mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE);
unmap(d, info->page, MALLOC_PAGESIZE); unmap(d, info->page, MALLOC_PAGESIZE);
@ -1119,55 +1064,54 @@ omalloc(size_t sz, int zero_fill)
size_t psz; size_t psz;
if (sz > MALLOC_MAXCHUNK) { if (sz > MALLOC_MAXCHUNK) {
if (sz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) {
if (sz >= SIZE_MAX - malloc_guard - MALLOC_PAGESIZE) {
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
} }
sz += mopts.malloc_guard;
sz += malloc_guard;
psz = PAGEROUND(sz); psz = PAGEROUND(sz);
p = map(g_pool, psz, zero_fill);
p = map(&g_pool, psz, zero_fill);
if (p == MAP_FAILED) { if (p == MAP_FAILED) {
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
} }
if (insert(g_pool, p, sz)) {
unmap(g_pool, p, psz);
if (insert(&g_pool, p, sz)) {
unmap(&g_pool, p, psz);
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
} }
if (mopts.malloc_guard) {
if (mprotect((char *)p + psz - mopts.malloc_guard,
mopts.malloc_guard, PROT_NONE))
if (malloc_guard) {
if (mprotect((char *)p + psz - malloc_guard,
malloc_guard, PROT_NONE))
wrterror("mprotect"); wrterror("mprotect");
malloc_guarded += mopts.malloc_guard;
malloc_guarded += malloc_guard;
} }
if (mopts.malloc_move &&
sz - mopts.malloc_guard < MALLOC_PAGESIZE -
MALLOC_LEEWAY) {
if (malloc_move &&
sz - malloc_guard < MALLOC_PAGESIZE - MALLOC_LEEWAY) {
/* fill whole allocation */ /* fill whole allocation */
if (mopts.malloc_junk)
memset(p, SOME_JUNK, psz - mopts.malloc_guard);
if (malloc_junk)
memset(p, SOME_JUNK, psz - malloc_guard);
/* shift towards the end */ /* shift towards the end */
p = ((char *)p) + ((MALLOC_PAGESIZE - MALLOC_LEEWAY - p = ((char *)p) + ((MALLOC_PAGESIZE - MALLOC_LEEWAY -
(sz - mopts.malloc_guard)) & ~(MALLOC_MINSIZE-1));
(sz - malloc_guard)) & ~(MALLOC_MINSIZE-1));
/* fill zeros if needed and overwritten above */ /* fill zeros if needed and overwritten above */
if (zero_fill && mopts.malloc_junk)
memset(p, 0, sz - mopts.malloc_guard);
if (zero_fill && malloc_junk)
memset(p, 0, sz - malloc_guard);
} else { } else {
if (mopts.malloc_junk) {
if (malloc_junk) {
if (zero_fill) if (zero_fill)
memset(p + sz - mopts.malloc_guard,
memset(p + sz - malloc_guard,
SOME_JUNK, psz - sz); SOME_JUNK, psz - sz);
else else
memset(p, SOME_JUNK,
psz - mopts.malloc_guard);
memset(p,
SOME_JUNK, psz - malloc_guard);
} }
} }
} else { } else {
/* takes care of SOME_JUNK */ /* takes care of SOME_JUNK */
p = malloc_bytes(g_pool, sz);
p = malloc_bytes(&g_pool, sz);
if (zero_fill && p != NULL && sz > 0) if (zero_fill && p != NULL && sz > 0)
memset(p, 0, sz); memset(p, 0, sz);
} }
@ -1194,27 +1138,6 @@ malloc_recurse(void)
errno = EDEADLK; errno = EDEADLK;
} }
static void
malloc_global_corrupt(void)
{
wrterror("global malloc data corrupt");
_MALLOC_UNLOCK();
errno = EINVAL;
}
static int
malloc_init(void)
{
if (omalloc_init(&g_pool)) {
_MALLOC_UNLOCK();
if (mopts.malloc_xmalloc)
wrterror("out of memory");
errno = ENOMEM;
return -1;
}
return 0;
}
void * void *
malloc(size_t size) malloc(size_t size)
{ {
@ -1223,18 +1146,23 @@ malloc(size_t size)
_MALLOC_LOCK(); _MALLOC_LOCK();
malloc_func = " in malloc():"; malloc_func = " in malloc():";
if (g_pool == NULL) {
if (malloc_init() != 0)
if (!g_pool.regions_total) {
if (omalloc_init(&g_pool)) {
_MALLOC_UNLOCK();
if (malloc_xmalloc)
wrterror("out of memory");
errno = ENOMEM;
return NULL; return NULL;
}
} }
if (malloc_active++) { if (malloc_active++) {
malloc_recurse(); malloc_recurse();
return NULL; return NULL;
} }
r = omalloc(size, mopts.malloc_zero);
r = omalloc(size, malloc_zero);
malloc_active--; malloc_active--;
_MALLOC_UNLOCK(); _MALLOC_UNLOCK();
if (r == NULL && mopts.malloc_xmalloc) {
if (r == NULL && malloc_xmalloc) {
wrterror("out of memory"); wrterror("out of memory");
errno = ENOMEM; errno = ENOMEM;
} }
@ -1249,15 +1177,14 @@ ofree(void *p)
struct region_info *r; struct region_info *r;
size_t sz; size_t sz;
r = find(g_pool, p);
r = find(&g_pool, p);
if (r == NULL) { if (r == NULL) {
wrterror("bogus pointer (double free?)"); wrterror("bogus pointer (double free?)");
return; return;
} }
REALSIZE(sz, r); REALSIZE(sz, r);
if (sz > MALLOC_MAXCHUNK) { if (sz > MALLOC_MAXCHUNK) {
if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE -
MALLOC_LEEWAY) {
if (sz - malloc_guard >= MALLOC_PAGESIZE - MALLOC_LEEWAY) {
if (r->p != p) { if (r->p != p) {
wrterror("bogus pointer"); wrterror("bogus pointer");
return; return;
@ -1266,47 +1193,46 @@ ofree(void *p)
#if notyetbecause_of_realloc #if notyetbecause_of_realloc
/* shifted towards the end */ /* shifted towards the end */
if (p != ((char *)r->p) + ((MALLOC_PAGESIZE - if (p != ((char *)r->p) + ((MALLOC_PAGESIZE -
MALLOC_MINSIZE - sz - mopts.malloc_guard) &
MALLOC_MINSIZE - sz - malloc_guard) &
~(MALLOC_MINSIZE-1))) { ~(MALLOC_MINSIZE-1))) {
} }
#endif #endif
p = r->p; p = r->p;
} }
if (mopts.malloc_guard) {
if (sz < mopts.malloc_guard)
if (malloc_guard) {
if (sz < malloc_guard)
wrterror("guard size"); wrterror("guard size");
if (!mopts.malloc_freeprot) {
if (!malloc_freeprot) {
if (mprotect((char *)p + PAGEROUND(sz) - if (mprotect((char *)p + PAGEROUND(sz) -
mopts.malloc_guard, mopts.malloc_guard,
malloc_guard, malloc_guard,
PROT_READ | PROT_WRITE)) PROT_READ | PROT_WRITE))
wrterror("mprotect"); wrterror("mprotect");
} }
malloc_guarded -= mopts.malloc_guard;
malloc_guarded -= malloc_guard;
} }
if (mopts.malloc_junk && !mopts.malloc_freeprot)
memset(p, SOME_FREEJUNK,
PAGEROUND(sz) - mopts.malloc_guard);
unmap(g_pool, p, PAGEROUND(sz));
delete(g_pool, r);
if (malloc_junk && !malloc_freeprot)
memset(p, SOME_FREEJUNK, PAGEROUND(sz) - malloc_guard);
unmap(&g_pool, p, PAGEROUND(sz));
delete(&g_pool, r);
} else { } else {
void *tmp; void *tmp;
int i; int i;
if (mopts.malloc_junk && sz > 0)
if (malloc_junk && sz > 0)
memset(p, SOME_FREEJUNK, sz); memset(p, SOME_FREEJUNK, sz);
if (!mopts.malloc_freeprot) {
if (!malloc_freeprot) {
i = getrbyte() & (MALLOC_DELAYED_CHUNKS - 1); i = getrbyte() & (MALLOC_DELAYED_CHUNKS - 1);
tmp = p; tmp = p;
p = g_pool->delayed_chunks[i];
g_pool->delayed_chunks[i] = tmp;
p = g_pool.delayed_chunks[i];
g_pool.delayed_chunks[i] = tmp;
} }
if (p != NULL) { if (p != NULL) {
r = find(g_pool, p);
r = find(&g_pool, p);
if (r == NULL) { if (r == NULL) {
wrterror("bogus pointer (double free?)"); wrterror("bogus pointer (double free?)");
return; return;
} }
free_bytes(g_pool, r, p);
free_bytes(&g_pool, r, p);
} }
} }
} }
@ -1322,11 +1248,6 @@ free(void *ptr)
_MALLOC_LOCK(); _MALLOC_LOCK();
malloc_func = " in free():"; malloc_func = " in free():";
if (g_pool == NULL) {
_MALLOC_UNLOCK();
wrterror("free() called before allocation");
return;
}
if (malloc_active++) { if (malloc_active++) {
malloc_recurse(); malloc_recurse();
return; return;
@ -1348,12 +1269,12 @@ orealloc(void *p, size_t newsz)
if (p == NULL) if (p == NULL)
return omalloc(newsz, 0); return omalloc(newsz, 0);
r = find(g_pool, p);
r = find(&g_pool, p);
if (r == NULL) { if (r == NULL) {
wrterror("bogus pointer (double free?)"); wrterror("bogus pointer (double free?)");
return NULL; return NULL;
} }
if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) {
if (newsz >= SIZE_MAX - malloc_guard - MALLOC_PAGESIZE) {
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
} }
@ -1361,63 +1282,61 @@ orealloc(void *p, size_t newsz)
REALSIZE(oldsz, r); REALSIZE(oldsz, r);
goldsz = oldsz; goldsz = oldsz;
if (oldsz > MALLOC_MAXCHUNK) { if (oldsz > MALLOC_MAXCHUNK) {
if (oldsz < mopts.malloc_guard)
if (oldsz < malloc_guard)
wrterror("guard size"); wrterror("guard size");
oldsz -= mopts.malloc_guard;
oldsz -= malloc_guard;
} }
gnewsz = newsz; gnewsz = newsz;
if (gnewsz > MALLOC_MAXCHUNK) if (gnewsz > MALLOC_MAXCHUNK)
gnewsz += mopts.malloc_guard;
gnewsz += malloc_guard;
if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p && if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p &&
!mopts.malloc_realloc) {
!malloc_realloc) {
size_t roldsz = PAGEROUND(goldsz); size_t roldsz = PAGEROUND(goldsz);
size_t rnewsz = PAGEROUND(gnewsz); size_t rnewsz = PAGEROUND(gnewsz);
if (rnewsz > roldsz) { if (rnewsz > roldsz) {
if (!mopts.malloc_guard) {
if (!malloc_guard) {
STATS_INC(g_pool.cheap_realloc_tries); STATS_INC(g_pool.cheap_realloc_tries);
zapcacheregion(g_pool, p + roldsz);
zapcacheregion(&g_pool, p + roldsz);
q = MMAPA(p + roldsz, rnewsz - roldsz); q = MMAPA(p + roldsz, rnewsz - roldsz);
if (q == p + roldsz) { if (q == p + roldsz) {
malloc_used += rnewsz - roldsz; malloc_used += rnewsz - roldsz;
if (mopts.malloc_junk)
if (malloc_junk)
memset(q, SOME_JUNK, memset(q, SOME_JUNK,
rnewsz - roldsz); rnewsz - roldsz);
r->size = newsz; r->size = newsz;
STATS_INC(g_pool->cheap_reallocs);
STATS_INC(g_pool.cheap_reallocs);
return p; return p;
} else if (q != MAP_FAILED) } else if (q != MAP_FAILED)
munmap(q, rnewsz - roldsz); munmap(q, rnewsz - roldsz);
} }
} else if (rnewsz < roldsz) { } else if (rnewsz < roldsz) {
if (mopts.malloc_guard) {
if (mprotect((char *)p + roldsz -
mopts.malloc_guard, mopts.malloc_guard,
PROT_READ | PROT_WRITE))
if (malloc_guard) {
if (mprotect((char *)p + roldsz - malloc_guard,
malloc_guard, PROT_READ | PROT_WRITE))
wrterror("mprotect"); wrterror("mprotect");
if (mprotect((char *)p + rnewsz -
mopts.malloc_guard, mopts.malloc_guard,
PROT_NONE))
if (mprotect((char *)p + rnewsz - malloc_guard,
malloc_guard, PROT_NONE))
wrterror("mprotect"); wrterror("mprotect");
} }
unmap(g_pool, (char *)p + rnewsz, roldsz - rnewsz);
unmap(&g_pool, (char *)p + rnewsz, roldsz - rnewsz);
r->size = gnewsz; r->size = gnewsz;
return p; return p;
} else { } else {
if (newsz > oldsz && mopts.malloc_junk)
if (newsz > oldsz && malloc_junk)
memset((char *)p + newsz, SOME_JUNK, memset((char *)p + newsz, SOME_JUNK,
rnewsz - mopts.malloc_guard - newsz);
rnewsz - malloc_guard - newsz);
r->size = gnewsz; r->size = gnewsz;
return p; return p;
} }
} }
if (newsz <= oldsz && newsz > oldsz / 2 && !mopts.malloc_realloc) {
if (mopts.malloc_junk && newsz > 0)
if (newsz <= oldsz && newsz > oldsz / 2 && !malloc_realloc) {
if (malloc_junk && newsz > 0)
memset((char *)p + newsz, SOME_JUNK, oldsz - newsz); memset((char *)p + newsz, SOME_JUNK, oldsz - newsz);
return p; return p;
} else if (newsz != oldsz || mopts.malloc_realloc) {
} else if (newsz != oldsz || malloc_realloc) {
q = omalloc(newsz, 0); q = omalloc(newsz, 0);
if (q == NULL) if (q == NULL)
return NULL; return NULL;
@ -1437,19 +1356,25 @@ realloc(void *ptr, size_t size)
_MALLOC_LOCK(); _MALLOC_LOCK();
malloc_func = " in realloc():"; malloc_func = " in realloc():";
if (g_pool == NULL) {
if (malloc_init() != 0)
if (!g_pool.regions_total) {
if (omalloc_init(&g_pool)) {
_MALLOC_UNLOCK();
if (malloc_xmalloc)
wrterror("out of memory");
errno = ENOMEM;
return NULL; return NULL;
}
} }
if (malloc_active++) { if (malloc_active++) {
malloc_recurse(); malloc_recurse();
return NULL; return NULL;
} }
r = orealloc(ptr, size); r = orealloc(ptr, size);
malloc_active--; malloc_active--;
_MALLOC_UNLOCK(); _MALLOC_UNLOCK();
if (r == NULL && mopts.malloc_xmalloc) {
if (r == NULL && malloc_xmalloc) {
wrterror("out of memory"); wrterror("out of memory");
errno = ENOMEM; errno = ENOMEM;
} }
@ -1469,14 +1394,19 @@ calloc(size_t nmemb, size_t size)
_MALLOC_LOCK(); _MALLOC_LOCK();
malloc_func = " in calloc():"; malloc_func = " in calloc():";
if (g_pool == NULL) {
if (malloc_init() != 0)
if (!g_pool.regions_total) {
if (omalloc_init(&g_pool)) {
_MALLOC_UNLOCK();
if (malloc_xmalloc)
wrterror("out of memory");
errno = ENOMEM;
return NULL; return NULL;
}
} }
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) { nmemb > 0 && SIZE_MAX / nmemb < size) {
_MALLOC_UNLOCK();
if (mopts.malloc_xmalloc)
_MALLOC_UNLOCK();
if (malloc_xmalloc)
wrterror("out of memory"); wrterror("out of memory");
errno = ENOMEM; errno = ENOMEM;
return NULL; return NULL;
@ -1492,7 +1422,7 @@ calloc(size_t nmemb, size_t size)
malloc_active--; malloc_active--;
_MALLOC_UNLOCK(); _MALLOC_UNLOCK();
if (r == NULL && mopts.malloc_xmalloc) {
if (r == NULL && malloc_xmalloc) {
wrterror("out of memory"); wrterror("out of memory");
errno = ENOMEM; errno = ENOMEM;
} }
@ -1500,4 +1430,3 @@ calloc(size_t nmemb, size_t size)
errno = saved_errno; errno = saved_errno;
return r; return r;
} }

Loading…
Cancel
Save