|
@ -8,12 +8,15 @@ |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
#if defined(LIBC_SCCS) && !defined(lint) |
|
|
#if defined(LIBC_SCCS) && !defined(lint) |
|
|
static char rcsid[] = "$OpenBSD: malloc.c,v 1.13 1996/09/19 20:38:48 tholo Exp $"; |
|
|
|
|
|
|
|
|
static char rcsid[] = "$OpenBSD: malloc.c,v 1.14 1996/09/26 04:19:42 tholo Exp $"; |
|
|
#endif /* LIBC_SCCS and not lint */ |
|
|
#endif /* LIBC_SCCS and not lint */ |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Defining EXTRA_SANITY will enable some checks which are related |
|
|
|
|
|
* to internal conditions and consistency in malloc.c |
|
|
|
|
|
|
|
|
* Defining EXTRA_SANITY will enable extra checks which are related |
|
|
|
|
|
* to internal conditions and consistency in malloc.c. This has a |
|
|
|
|
|
* noticeable runtime performance hit, and generally will not do you |
|
|
|
|
|
* any good unless you fiddle with the internals of malloc or want |
|
|
|
|
|
* to catch random pointer corruption as early as possible. |
|
|
*/ |
|
|
*/ |
|
|
#undef EXTRA_SANITY |
|
|
#undef EXTRA_SANITY |
|
|
|
|
|
|
|
@ -29,23 +32,23 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.13 1996/09/19 20:38:48 tholo Exp $ |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* What to use for Junk |
|
|
|
|
|
|
|
|
* What to use for Junk. This is the byte value we use to fill with |
|
|
|
|
|
* when the 'J' option is enabled. |
|
|
*/ |
|
|
*/ |
|
|
#define SOME_JUNK 0xd0 /* as in "Duh" :-) */ |
|
|
#define SOME_JUNK 0xd0 /* as in "Duh" :-) */ |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* No user serviceable parts behind this point. |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <stdlib.h> |
|
|
|
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
|
#include <unistd.h> |
|
|
#include <memory.h> |
|
|
|
|
|
#include <errno.h> |
|
|
#include <errno.h> |
|
|
#include <err.h> |
|
|
|
|
|
#include <sys/types.h> |
|
|
#include <sys/types.h> |
|
|
#include <sys/param.h> |
|
|
#include <sys/param.h> |
|
|
#include <sys/mman.h> |
|
|
#include <sys/mman.h> |
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
#include <pthread.h> |
|
|
|
|
|
#include "pthread_private.h" |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* If these weren't defined here, they would be calculated on the fly, |
|
|
* If these weren't defined here, they would be calculated on the fly, |
|
@ -108,14 +111,14 @@ struct pgfree { |
|
|
* We might as well use them. There are C-language backups, but |
|
|
* We might as well use them. There are C-language backups, but |
|
|
* they are considerably slower. |
|
|
* they are considerably slower. |
|
|
*/ |
|
|
*/ |
|
|
#ifdef __i386__ |
|
|
|
|
|
|
|
|
#if defined(__i386__) && defined(__GNUC__) |
|
|
#define ffs _ffs |
|
|
#define ffs _ffs |
|
|
static __inline int |
|
|
static __inline int |
|
|
_ffs(input) |
|
|
_ffs(input) |
|
|
unsigned input; |
|
|
unsigned input; |
|
|
{ |
|
|
{ |
|
|
int result; |
|
|
int result; |
|
|
__asm("bsfl %1,%0" : "=r" (result) : "r" (input)); |
|
|
|
|
|
|
|
|
__asm("bsfl %1, %0" : "=r" (result) : "r" (input)); |
|
|
return result+1; |
|
|
return result+1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -125,7 +128,7 @@ _fls(input) |
|
|
unsigned input; |
|
|
unsigned input; |
|
|
{ |
|
|
{ |
|
|
int result; |
|
|
int result; |
|
|
__asm("bsrl %1,%0" : "=r" (result) : "r" (input)); |
|
|
|
|
|
|
|
|
__asm("bsrl %1, %0" : "=r" (result) : "r" (input)); |
|
|
return result+1; |
|
|
return result+1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -135,7 +138,7 @@ _set_bit(pi, bit) |
|
|
struct pginfo *pi; |
|
|
struct pginfo *pi; |
|
|
int bit; |
|
|
int bit; |
|
|
{ |
|
|
{ |
|
|
__asm("btsl %0,(%1)" : |
|
|
|
|
|
|
|
|
__asm("btsl %0, (%1)" : |
|
|
: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); |
|
|
: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -145,11 +148,11 @@ _clr_bit(pi, bit) |
|
|
struct pginfo *pi; |
|
|
struct pginfo *pi; |
|
|
int bit; |
|
|
int bit; |
|
|
{ |
|
|
{ |
|
|
__asm("btcl %0,(%1)" : |
|
|
|
|
|
|
|
|
__asm("btcl %0, (%1)" : |
|
|
: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); |
|
|
: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS))); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#endif /* __i386__ */ |
|
|
|
|
|
|
|
|
#endif /* __i386__ && __GNUC__ */ |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Set to one when malloc_init has been called |
|
|
* Set to one when malloc_init has been called |
|
@ -165,17 +168,13 @@ static unsigned initialized; |
|
|
static unsigned malloc_pagesize; |
|
|
static unsigned malloc_pagesize; |
|
|
#endif /* malloc_pagesize */ |
|
|
#endif /* malloc_pagesize */ |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* A mask for the offset inside a page. |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* A mask for the offset inside a page. */ |
|
|
#define malloc_pagemask ((malloc_pagesize)-1) |
|
|
#define malloc_pagemask ((malloc_pagesize)-1) |
|
|
|
|
|
|
|
|
#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) |
|
|
#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) |
|
|
#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) |
|
|
#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* malloc_pagesize == 1 << malloc_pageshift |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* malloc_pagesize == 1 << malloc_pageshift */ |
|
|
#ifndef malloc_pageshift |
|
|
#ifndef malloc_pageshift |
|
|
static unsigned malloc_pageshift; |
|
|
static unsigned malloc_pageshift; |
|
|
#endif /* malloc_pageshift */ |
|
|
#endif /* malloc_pageshift */ |
|
@ -197,85 +196,78 @@ static unsigned malloc_minsize; |
|
|
static unsigned malloc_maxsize; |
|
|
static unsigned malloc_maxsize; |
|
|
#endif /* malloc_maxsize */ |
|
|
#endif /* malloc_maxsize */ |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* The minimum size (in bytes) of the free page cache. |
|
|
|
|
|
*/ |
|
|
|
|
|
#ifndef malloc_cache |
|
|
|
|
|
static unsigned malloc_cache; |
|
|
|
|
|
#endif /* malloc_cache */ |
|
|
|
|
|
|
|
|
/* The minimum size (in pages) of the free page cache. */ |
|
|
|
|
|
static unsigned malloc_cache = 16; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* The offset from pagenumber to index into the page directory |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* The offset from pagenumber to index into the page directory */ |
|
|
static u_long malloc_origo; |
|
|
static u_long malloc_origo; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* The last index in the page directory we care about |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* The last index in the page directory we care about */ |
|
|
static u_long last_index; |
|
|
static u_long last_index; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* Pointer to page directory. |
|
|
|
|
|
* Allocated "as if with" malloc |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* Pointer to page directory. Allocated "as if with" malloc */ |
|
|
static struct pginfo **page_dir; |
|
|
static struct pginfo **page_dir; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* How many slots in the page directory |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* How many slots in the page directory */ |
|
|
static unsigned malloc_ninfo; |
|
|
static unsigned malloc_ninfo; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* Free pages line up here |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* Free pages line up here */ |
|
|
static struct pgfree free_list; |
|
|
static struct pgfree free_list; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* Abort() if we fail to get VM ? |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* Abort(), user doesn't handle problems. */ |
|
|
static int malloc_abort; |
|
|
static int malloc_abort; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* Are we trying to die ? |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* Are we trying to die ? */ |
|
|
static int suicide; |
|
|
static int suicide; |
|
|
|
|
|
|
|
|
#ifdef MALLOC_STATS |
|
|
#ifdef MALLOC_STATS |
|
|
/* |
|
|
|
|
|
* dump statistics |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* dump statistics */ |
|
|
static int malloc_stats; |
|
|
static int malloc_stats; |
|
|
#endif /* MALLOC_STATS */ |
|
|
#endif /* MALLOC_STATS */ |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* always realloc ? |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* always realloc ? */ |
|
|
static int malloc_realloc; |
|
|
static int malloc_realloc; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* zero fill ? |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__ |
|
|
|
|
|
/* pass the kernel a hint on free pages ? */ |
|
|
|
|
|
static int malloc_hint; |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* zero fill ? */ |
|
|
static int malloc_zero; |
|
|
static int malloc_zero; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* junk fill ? |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* junk fill ? */ |
|
|
static int malloc_junk; |
|
|
static int malloc_junk; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* my last break. |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__ |
|
|
|
|
|
/* utrace ? */ |
|
|
|
|
|
static int malloc_utrace; |
|
|
|
|
|
|
|
|
|
|
|
struct ut { void *p; size_t s; void *r; }; |
|
|
|
|
|
|
|
|
|
|
|
#define UTRACE(a, b, c) \ |
|
|
|
|
|
if (malloc_utrace) \ |
|
|
|
|
|
{struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);} |
|
|
|
|
|
#else /* !__FreeBSD__ */ |
|
|
|
|
|
#define UTRACE(a,b,c) |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* my last break. */ |
|
|
static void *malloc_brk; |
|
|
static void *malloc_brk; |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* one location cache for free-list holders |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
/* one location cache for free-list holders */ |
|
|
static struct pgfree *px; |
|
|
static struct pgfree *px; |
|
|
|
|
|
|
|
|
|
|
|
/* compile-time options */ |
|
|
|
|
|
char *malloc_options; |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Necessary function declarations |
|
|
* Necessary function declarations |
|
|
*/ |
|
|
*/ |
|
|
static int extend_pgdir(u_long index); |
|
|
static int extend_pgdir(u_long index); |
|
|
|
|
|
static void *imalloc(size_t size); |
|
|
|
|
|
static void ifree(void *ptr); |
|
|
|
|
|
static void *irealloc(void *ptr, size_t size); |
|
|
|
|
|
|
|
|
#ifdef MALLOC_STATS |
|
|
#ifdef MALLOC_STATS |
|
|
void |
|
|
void |
|
@ -290,60 +282,63 @@ malloc_dump(fd) |
|
|
|
|
|
|
|
|
/* print out all the pages */ |
|
|
/* print out all the pages */ |
|
|
for(j=0;j<=last_index;j++) { |
|
|
for(j=0;j<=last_index;j++) { |
|
|
fprintf(fd,"%08lx %5d ",(j+malloc_origo) << malloc_pageshift,j); |
|
|
|
|
|
|
|
|
fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j); |
|
|
if (pd[j] == MALLOC_NOT_MINE) { |
|
|
if (pd[j] == MALLOC_NOT_MINE) { |
|
|
for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) |
|
|
for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) |
|
|
; |
|
|
; |
|
|
j--; |
|
|
j--; |
|
|
fprintf(fd,".. %5d not mine\n", j); |
|
|
|
|
|
|
|
|
fprintf(fd, ".. %5d not mine\n", j); |
|
|
} else if (pd[j] == MALLOC_FREE) { |
|
|
} else if (pd[j] == MALLOC_FREE) { |
|
|
for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) |
|
|
for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) |
|
|
; |
|
|
; |
|
|
j--; |
|
|
j--; |
|
|
fprintf(fd,".. %5d free\n", j); |
|
|
|
|
|
|
|
|
fprintf(fd, ".. %5d free\n", j); |
|
|
} else if (pd[j] == MALLOC_FIRST) { |
|
|
} else if (pd[j] == MALLOC_FIRST) { |
|
|
for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) |
|
|
for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) |
|
|
; |
|
|
; |
|
|
j--; |
|
|
j--; |
|
|
fprintf(fd,".. %5d in use\n", j); |
|
|
|
|
|
|
|
|
fprintf(fd, ".. %5d in use\n", j); |
|
|
} else if (pd[j] < MALLOC_MAGIC) { |
|
|
} else if (pd[j] < MALLOC_MAGIC) { |
|
|
fprintf(fd,"(%p)\n", pd[j]); |
|
|
|
|
|
|
|
|
fprintf(fd, "(%p)\n", pd[j]); |
|
|
} else { |
|
|
} else { |
|
|
fprintf(fd,"%p %d (of %d) x %d @ %p --> %p\n", |
|
|
|
|
|
pd[j],pd[j]->free, pd[j]->total, |
|
|
|
|
|
|
|
|
fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", |
|
|
|
|
|
pd[j], pd[j]->free, pd[j]->total, |
|
|
pd[j]->size, pd[j]->page, pd[j]->next); |
|
|
pd[j]->size, pd[j]->page, pd[j]->next); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for(pf=free_list.next; pf; pf=pf->next) { |
|
|
for(pf=free_list.next; pf; pf=pf->next) { |
|
|
fprintf(fd,"Free: @%p [%p...%p[ %ld ->%p <-%p\n", |
|
|
|
|
|
pf,pf->page,pf->end,pf->size,pf->prev,pf->next); |
|
|
|
|
|
|
|
|
fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", |
|
|
|
|
|
pf, pf->page, pf->end, pf->size, pf->prev, pf->next); |
|
|
if (pf == pf->next) { |
|
|
if (pf == pf->next) { |
|
|
fprintf(fd,"Free_list loops.\n"); |
|
|
|
|
|
|
|
|
+ fprintf(fd, "Free_list loops.\n"); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* print out various info */ |
|
|
/* print out various info */ |
|
|
fprintf(fd,"Minsize\t%d\n",malloc_minsize); |
|
|
|
|
|
fprintf(fd,"Maxsize\t%d\n",malloc_maxsize); |
|
|
|
|
|
fprintf(fd,"Pagesize\t%d\n",malloc_pagesize); |
|
|
|
|
|
fprintf(fd,"Pageshift\t%d\n",malloc_pageshift); |
|
|
|
|
|
fprintf(fd,"FirstPage\t%ld\n",malloc_origo); |
|
|
|
|
|
fprintf(fd,"LastPage\t%ld %lx\n",last_index+malloc_pageshift, |
|
|
|
|
|
|
|
|
fprintf(fd, "Minsize\t%d\n", malloc_minsize); |
|
|
|
|
|
fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); |
|
|
|
|
|
fprintf(fd, "Pagesize\t%d\n", malloc_pagesize); |
|
|
|
|
|
fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); |
|
|
|
|
|
fprintf(fd, "FirstPage\t%ld\n", malloc_origo); |
|
|
|
|
|
fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift, |
|
|
(last_index + malloc_pageshift) << malloc_pageshift); |
|
|
(last_index + malloc_pageshift) << malloc_pageshift); |
|
|
fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift); |
|
|
|
|
|
|
|
|
fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift); |
|
|
} |
|
|
} |
|
|
#endif /* MALLOC_STATS */ |
|
|
#endif /* MALLOC_STATS */ |
|
|
|
|
|
|
|
|
|
|
|
static char *malloc_func; |
|
|
|
|
|
|
|
|
static void |
|
|
static void |
|
|
wrterror(p) |
|
|
wrterror(p) |
|
|
char *p; |
|
|
char *p; |
|
|
{ |
|
|
{ |
|
|
char *q = "Malloc error: "; |
|
|
char *q = "Malloc error: "; |
|
|
suicide = 1; |
|
|
suicide = 1; |
|
|
write(2,q,strlen(q)); |
|
|
|
|
|
write(2,p,strlen(p)); |
|
|
|
|
|
|
|
|
write(2, q, strlen(q)); |
|
|
|
|
|
write(2, malloc_func, strlen(malloc_func)); |
|
|
|
|
|
write(2, p, strlen(p)); |
|
|
#ifdef MALLOC_STATS |
|
|
#ifdef MALLOC_STATS |
|
|
if (malloc_stats) |
|
|
if (malloc_stats) |
|
|
malloc_dump(stderr); |
|
|
malloc_dump(stderr); |
|
@ -358,21 +353,22 @@ wrtwarning(p) |
|
|
char *q = "Malloc warning: "; |
|
|
char *q = "Malloc warning: "; |
|
|
if (malloc_abort) |
|
|
if (malloc_abort) |
|
|
wrterror(p); |
|
|
wrterror(p); |
|
|
write(2,q,strlen(q)); |
|
|
|
|
|
write(2,p,strlen(p)); |
|
|
|
|
|
|
|
|
write(2, q, strlen(q)); |
|
|
|
|
|
write(2, malloc_func, strlen(malloc_func)); |
|
|
|
|
|
write(2, p, strlen(p)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef EXTRA_SANITY |
|
|
#ifdef EXTRA_SANITY |
|
|
static void |
|
|
static void |
|
|
malloc_exit() |
|
|
malloc_exit() |
|
|
{ |
|
|
{ |
|
|
FILE *fd = fopen("malloc.out","a"); |
|
|
|
|
|
|
|
|
FILE *fd = fopen("malloc.out", "a"); |
|
|
char *q = "malloc() warning: Couldn't dump stats.\n"; |
|
|
char *q = "malloc() warning: Couldn't dump stats.\n"; |
|
|
if (fd) { |
|
|
if (fd) { |
|
|
malloc_dump(fd); |
|
|
malloc_dump(fd); |
|
|
fclose(fd); |
|
|
fclose(fd); |
|
|
} else |
|
|
} else |
|
|
write(2,q,strlen(q)); |
|
|
|
|
|
|
|
|
write(2, q, strlen(q)); |
|
|
} |
|
|
} |
|
|
#endif /* EXTRA_SANITY */ |
|
|
#endif /* EXTRA_SANITY */ |
|
|
|
|
|
|
|
@ -384,14 +380,14 @@ static caddr_t |
|
|
map_pages(pages) |
|
|
map_pages(pages) |
|
|
int pages; |
|
|
int pages; |
|
|
{ |
|
|
{ |
|
|
caddr_t result,tail; |
|
|
|
|
|
|
|
|
caddr_t result, tail; |
|
|
|
|
|
|
|
|
result = (caddr_t)pageround((u_long)sbrk(0)); |
|
|
result = (caddr_t)pageround((u_long)sbrk(0)); |
|
|
tail = result + (pages << malloc_pageshift); |
|
|
tail = result + (pages << malloc_pageshift); |
|
|
|
|
|
|
|
|
if (brk(tail)) { |
|
|
if (brk(tail)) { |
|
|
#ifdef EXTRA_SANITY |
|
|
#ifdef EXTRA_SANITY |
|
|
wrterror("(internal): map_pages fails\n"); |
|
|
|
|
|
|
|
|
wrterror("(ES): map_pages fails\n"); |
|
|
#endif /* EXTRA_SANITY */ |
|
|
#endif /* EXTRA_SANITY */ |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
@ -466,7 +462,7 @@ static int |
|
|
extend_pgdir(index) |
|
|
extend_pgdir(index) |
|
|
u_long index; |
|
|
u_long index; |
|
|
{ |
|
|
{ |
|
|
struct pginfo **new,**old; |
|
|
|
|
|
|
|
|
struct pginfo **new, **old; |
|
|
int i, oldlen; |
|
|
int i, oldlen; |
|
|
|
|
|
|
|
|
/* Make it this many pages */ |
|
|
/* Make it this many pages */ |
|
@ -520,35 +516,61 @@ extend_pgdir(index) |
|
|
static void |
|
|
static void |
|
|
malloc_init () |
|
|
malloc_init () |
|
|
{ |
|
|
{ |
|
|
char *p; |
|
|
|
|
|
|
|
|
char *p, b[64]; |
|
|
|
|
|
int i, j; |
|
|
|
|
|
|
|
|
#ifdef EXTRA_SANITY |
|
|
#ifdef EXTRA_SANITY |
|
|
malloc_junk = 1; |
|
|
malloc_junk = 1; |
|
|
#endif /* EXTRA_SANITY */ |
|
|
#endif /* EXTRA_SANITY */ |
|
|
|
|
|
|
|
|
if (issetugid() == 0) { |
|
|
|
|
|
for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) { |
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) { |
|
|
|
|
|
if (i == 0) { |
|
|
|
|
|
j = readlink("/etc/malloc.conf", b, sizeof b - 1); |
|
|
|
|
|
if (j <= 0) |
|
|
|
|
|
continue; |
|
|
|
|
|
b[j] = '\0'; |
|
|
|
|
|
p = b; |
|
|
|
|
|
} else if (i == 1) { |
|
|
|
|
|
p = getenv("MALLOC_OPTIONS"); |
|
|
|
|
|
} else if (i == 2) { |
|
|
|
|
|
p = malloc_options; |
|
|
|
|
|
} |
|
|
|
|
|
for (; p && *p; p++) { |
|
|
switch (*p) { |
|
|
switch (*p) { |
|
|
case 'a': malloc_abort = 0; break; |
|
|
|
|
|
case 'A': malloc_abort = 1; break; |
|
|
|
|
|
|
|
|
case '>': malloc_cache <<= 1; break; |
|
|
|
|
|
case '<': malloc_cache >>= 1; break; |
|
|
|
|
|
case 'a': malloc_abort = 0; break; |
|
|
|
|
|
case 'A': malloc_abort = 1; break; |
|
|
#ifdef MALLOC_STATS |
|
|
#ifdef MALLOC_STATS |
|
|
case 'd': malloc_stats = 0; break; |
|
|
|
|
|
case 'D': malloc_stats = 1; break; |
|
|
|
|
|
|
|
|
case 'd': malloc_stats = 0; break; |
|
|
|
|
|
case 'D': malloc_stats = 1; break; |
|
|
#endif /* MALLOC_STATS */ |
|
|
#endif /* MALLOC_STATS */ |
|
|
case 'r': malloc_realloc = 0; break; |
|
|
|
|
|
case 'R': malloc_realloc = 1; break; |
|
|
|
|
|
case 'j': malloc_junk = 0; break; |
|
|
|
|
|
case 'J': malloc_junk = 1; break; |
|
|
|
|
|
case 'z': malloc_zero = 0; break; |
|
|
|
|
|
case 'Z': malloc_zero = 1; break; |
|
|
|
|
|
default: |
|
|
|
|
|
wrtwarning("(Init): Unknown char in MALLOC_OPTIONS\n"); |
|
|
|
|
|
p = 0; |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__ |
|
|
|
|
|
case 'h': malloc_hint = 0; break; |
|
|
|
|
|
case 'H': malloc_hint = 1; break; |
|
|
|
|
|
#endif /* __FreeBSD__ */ |
|
|
|
|
|
case 'r': malloc_realloc = 0; break; |
|
|
|
|
|
case 'R': malloc_realloc = 1; break; |
|
|
|
|
|
case 'j': malloc_junk = 0; break; |
|
|
|
|
|
case 'J': malloc_junk = 1; break; |
|
|
|
|
|
#ifdef __FreeBSD__ |
|
|
|
|
|
case 'u': malloc_utrace = 0; break; |
|
|
|
|
|
case 'U': malloc_utrace = 1; break; |
|
|
|
|
|
#endif /* __FreeBSD__ */ |
|
|
|
|
|
case 'z': malloc_zero = 0; break; |
|
|
|
|
|
case 'Z': malloc_zero = 1; break; |
|
|
|
|
|
default: |
|
|
|
|
|
j = malloc_abort; |
|
|
|
|
|
malloc_abort = 0; |
|
|
|
|
|
wrtwarning("unknown char in MALLOC_OPTIONS\n"); |
|
|
|
|
|
malloc_abort = j; |
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
UTRACE(0, 0, 0); |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* 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. |
|
@ -579,10 +601,6 @@ malloc_init () |
|
|
} |
|
|
} |
|
|
#endif /* malloc_pageshift */ |
|
|
#endif /* malloc_pageshift */ |
|
|
|
|
|
|
|
|
#ifndef malloc_cache |
|
|
|
|
|
malloc_cache = 100 << malloc_pageshift; |
|
|
|
|
|
#endif /* malloc_cache */ |
|
|
|
|
|
|
|
|
|
|
|
#ifndef malloc_minsize |
|
|
#ifndef malloc_minsize |
|
|
{ |
|
|
{ |
|
|
int i; |
|
|
int i; |
|
@ -612,7 +630,7 @@ malloc_init () |
|
|
page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE, |
|
|
page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE, |
|
|
MAP_ANON|MAP_PRIVATE, -1, (off_t)0); |
|
|
MAP_ANON|MAP_PRIVATE, -1, (off_t)0); |
|
|
if (page_dir == (struct pginfo **) -1) |
|
|
if (page_dir == (struct pginfo **) -1) |
|
|
wrterror("(Init) my first mmap failed. (check limits ?)\n"); |
|
|
|
|
|
|
|
|
wrterror("mmap(2) failed, check limits.\n"); |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* We need a maximum of malloc_pageshift buckets, steal these from the |
|
|
* We need a maximum of malloc_pageshift buckets, steal these from the |
|
@ -630,7 +648,12 @@ malloc_init () |
|
|
* This is a nice hack from Kaleb Keithly (kaleb@x.org). |
|
|
* This is a nice hack from Kaleb Keithly (kaleb@x.org). |
|
|
* We can sbrk(2) further back when we keep this on a low address. |
|
|
* We can sbrk(2) further back when we keep this on a low address. |
|
|
*/ |
|
|
*/ |
|
|
px = (struct pgfree *) malloc (sizeof *px); |
|
|
|
|
|
|
|
|
px = (struct pgfree *) imalloc (sizeof *px); |
|
|
|
|
|
|
|
|
|
|
|
if (!malloc_cache) |
|
|
|
|
|
malloc_cache++; |
|
|
|
|
|
|
|
|
|
|
|
malloc_cache <<= malloc_pageshift; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
@ -640,7 +663,7 @@ void * |
|
|
malloc_pages(size) |
|
|
malloc_pages(size) |
|
|
size_t size; |
|
|
size_t size; |
|
|
{ |
|
|
{ |
|
|
void *p,*delay_free = 0; |
|
|
|
|
|
|
|
|
void *p, *delay_free = 0; |
|
|
int i; |
|
|
int i; |
|
|
struct pgfree *pf; |
|
|
struct pgfree *pf; |
|
|
u_long index; |
|
|
u_long index; |
|
@ -705,14 +728,14 @@ malloc_pages(size) |
|
|
page_dir[index+i] = MALLOC_FOLLOW; |
|
|
page_dir[index+i] = MALLOC_FOLLOW; |
|
|
|
|
|
|
|
|
if (malloc_junk) |
|
|
if (malloc_junk) |
|
|
memset(p, SOME_JUNK,size << malloc_pageshift); |
|
|
|
|
|
|
|
|
memset(p, SOME_JUNK, size << malloc_pageshift); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (delay_free) { |
|
|
if (delay_free) { |
|
|
if (!px) |
|
|
if (!px) |
|
|
px = delay_free; |
|
|
px = delay_free; |
|
|
else |
|
|
else |
|
|
free(delay_free); |
|
|
|
|
|
|
|
|
ifree(delay_free); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return p; |
|
|
return p; |
|
@ -728,7 +751,7 @@ malloc_make_chunks(bits) |
|
|
{ |
|
|
{ |
|
|
struct pginfo *bp; |
|
|
struct pginfo *bp; |
|
|
void *pp; |
|
|
void *pp; |
|
|
int i,k,l; |
|
|
|
|
|
|
|
|
int i, k, l; |
|
|
|
|
|
|
|
|
/* Allocate a new bucket */ |
|
|
/* Allocate a new bucket */ |
|
|
pp = malloc_pages(malloc_pagesize); |
|
|
pp = malloc_pages(malloc_pagesize); |
|
@ -744,7 +767,7 @@ malloc_make_chunks(bits) |
|
|
if ((1<<(bits)) <= l+l) { |
|
|
if ((1<<(bits)) <= l+l) { |
|
|
bp = (struct pginfo *)pp; |
|
|
bp = (struct pginfo *)pp; |
|
|
} else { |
|
|
} else { |
|
|
bp = (struct pginfo *)malloc(l); |
|
|
|
|
|
|
|
|
bp = (struct pginfo *)imalloc(l); |
|
|
if (!bp) |
|
|
if (!bp) |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
@ -768,12 +791,12 @@ malloc_make_chunks(bits) |
|
|
bp->bits[i / MALLOC_BITS] = (u_long)~0; |
|
|
bp->bits[i / MALLOC_BITS] = (u_long)~0; |
|
|
|
|
|
|
|
|
for(; i < k; i++) |
|
|
for(; i < k; i++) |
|
|
set_bit(bp,i); |
|
|
|
|
|
|
|
|
set_bit(bp, i); |
|
|
|
|
|
|
|
|
if (bp == bp->page) { |
|
|
if (bp == bp->page) { |
|
|
/* Mark the ones we stole for ourselves */ |
|
|
/* Mark the ones we stole for ourselves */ |
|
|
for(i=0;l > 0;i++) { |
|
|
for(i=0;l > 0;i++) { |
|
|
clr_bit(bp,i); |
|
|
|
|
|
|
|
|
clr_bit(bp, i); |
|
|
bp->free--; |
|
|
bp->free--; |
|
|
bp->total--; |
|
|
bp->total--; |
|
|
l -= (1 << bits); |
|
|
l -= (1 << bits); |
|
@ -835,8 +858,8 @@ malloc_bytes(size) |
|
|
/* |
|
|
/* |
|
|
* Allocate a piece of memory |
|
|
* Allocate a piece of memory |
|
|
*/ |
|
|
*/ |
|
|
void * |
|
|
|
|
|
malloc(size) |
|
|
|
|
|
|
|
|
static void * |
|
|
|
|
|
imalloc(size) |
|
|
size_t size; |
|
|
size_t size; |
|
|
{ |
|
|
{ |
|
|
void *result; |
|
|
void *result; |
|
@ -850,36 +873,30 @@ malloc(size) |
|
|
if (suicide) |
|
|
if (suicide) |
|
|
abort(); |
|
|
abort(); |
|
|
|
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_block(&status); |
|
|
|
|
|
#endif |
|
|
|
|
|
if (size <= malloc_maxsize) |
|
|
if (size <= malloc_maxsize) |
|
|
result = malloc_bytes(size); |
|
|
result = malloc_bytes(size); |
|
|
else |
|
|
else |
|
|
result = malloc_pages(size); |
|
|
result = malloc_pages(size); |
|
|
|
|
|
|
|
|
if (malloc_abort && !result) |
|
|
if (malloc_abort && !result) |
|
|
wrterror("malloc(): returns NULL\n"); |
|
|
|
|
|
|
|
|
wrterror("allocation failed.\n"); |
|
|
|
|
|
|
|
|
if (malloc_zero) |
|
|
if (malloc_zero) |
|
|
memset(result,0,size); |
|
|
|
|
|
|
|
|
memset(result, 0, size); |
|
|
|
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Change the size of an allocation. |
|
|
* Change the size of an allocation. |
|
|
*/ |
|
|
*/ |
|
|
void * |
|
|
|
|
|
realloc(ptr, size) |
|
|
|
|
|
|
|
|
static void * |
|
|
|
|
|
irealloc(ptr, size) |
|
|
void *ptr; |
|
|
void *ptr; |
|
|
size_t size; |
|
|
size_t size; |
|
|
{ |
|
|
{ |
|
|
void *p; |
|
|
void *p; |
|
|
u_long osize,index; |
|
|
|
|
|
|
|
|
u_long osize, index; |
|
|
struct pginfo **mp; |
|
|
struct pginfo **mp; |
|
|
int i; |
|
|
int i; |
|
|
#ifdef _THREAD_SAFE |
|
|
#ifdef _THREAD_SAFE |
|
@ -889,37 +906,20 @@ realloc(ptr, size) |
|
|
if (suicide) |
|
|
if (suicide) |
|
|
return 0; |
|
|
return 0; |
|
|
|
|
|
|
|
|
if (!ptr) /* Bounce to malloc() */ |
|
|
|
|
|
return malloc(size); |
|
|
|
|
|
|
|
|
|
|
|
if (!initialized) { |
|
|
if (!initialized) { |
|
|
wrtwarning("realloc(): malloc() never got called.\n"); |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (ptr && !size) { /* Bounce to free() */ |
|
|
|
|
|
free(ptr); |
|
|
|
|
|
|
|
|
wrtwarning("malloc() has never been called.\n"); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_block(&status); |
|
|
|
|
|
#endif |
|
|
|
|
|
index = ptr2index(ptr); |
|
|
index = ptr2index(ptr); |
|
|
|
|
|
|
|
|
if (index < malloc_pageshift) { |
|
|
if (index < malloc_pageshift) { |
|
|
wrtwarning("realloc(): junk pointer (too low)\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
wrtwarning("junk pointer, too low to make sense.\n"); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (index > last_index) { |
|
|
if (index > last_index) { |
|
|
wrtwarning("realloc(): junk pointer (too high)\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
wrtwarning("junk pointer, too high to make sense.\n"); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -929,10 +929,7 @@ realloc(ptr, size) |
|
|
|
|
|
|
|
|
/* Check the pointer */ |
|
|
/* Check the pointer */ |
|
|
if ((u_long)ptr & malloc_pagemask) { |
|
|
if ((u_long)ptr & malloc_pagemask) { |
|
|
wrtwarning("realloc(): modified page pointer.\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
wrtwarning("modified (page-) pointer.\n"); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -943,9 +940,6 @@ realloc(ptr, size) |
|
|
if (!malloc_realloc && /* unless we have to, */ |
|
|
if (!malloc_realloc && /* unless we have to, */ |
|
|
size <= osize && /* .. or are too small, */ |
|
|
size <= osize && /* .. or are too small, */ |
|
|
size > (osize - malloc_pagesize)) { /* .. or can free a page, */ |
|
|
size > (osize - malloc_pagesize)) { /* .. or can free a page, */ |
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
return ptr; /* don't do anything. */ |
|
|
return ptr; /* don't do anything. */ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -953,10 +947,7 @@ realloc(ptr, size) |
|
|
|
|
|
|
|
|
/* Check the pointer for sane values */ |
|
|
/* Check the pointer for sane values */ |
|
|
if (((u_long)ptr & ((*mp)->size-1))) { |
|
|
if (((u_long)ptr & ((*mp)->size-1))) { |
|
|
wrtwarning("realloc(): modified chunk pointer.\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
wrtwarning("modified (chunk-) pointer.\n"); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -964,11 +955,8 @@ realloc(ptr, size) |
|
|
i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift; |
|
|
i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift; |
|
|
|
|
|
|
|
|
/* Verify that it isn't a free chunk already */ |
|
|
/* Verify that it isn't a free chunk already */ |
|
|
if (tst_bit(*mp,i)) { |
|
|
|
|
|
wrtwarning("realloc(): already free chunk.\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
if (tst_bit(*mp, i)) { |
|
|
|
|
|
wrtwarning("chunk is already free.\n"); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -978,33 +966,24 @@ realloc(ptr, size) |
|
|
size < osize && /* ..or are too small, */ |
|
|
size < osize && /* ..or are too small, */ |
|
|
(size > osize/2 || /* ..or could use a smaller size, */ |
|
|
(size > osize/2 || /* ..or could use a smaller size, */ |
|
|
osize == malloc_minsize)) { /* ..(if there is one) */ |
|
|
osize == malloc_minsize)) { /* ..(if there is one) */ |
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
return ptr; /* ..Don't do anything */ |
|
|
return ptr; /* ..Don't do anything */ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} else { |
|
|
} else { |
|
|
wrtwarning("realloc(): wrong page pointer.\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
wrtwarning("pointer to wrong page.\n"); |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
p = malloc(size); |
|
|
|
|
|
|
|
|
p = imalloc(size); |
|
|
|
|
|
|
|
|
if (p) { |
|
|
if (p) { |
|
|
/* copy the lesser of the two sizes, and free the old one */ |
|
|
/* copy the lesser of the two sizes, and free the old one */ |
|
|
if (osize < size) |
|
|
if (osize < size) |
|
|
memcpy(p,ptr,osize); |
|
|
|
|
|
|
|
|
memcpy(p, ptr, osize); |
|
|
else |
|
|
else |
|
|
memcpy(p,ptr,size); |
|
|
|
|
|
free(ptr); |
|
|
|
|
|
|
|
|
memcpy(p, ptr, size); |
|
|
|
|
|
ifree(ptr); |
|
|
} |
|
|
} |
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
return p; |
|
|
return p; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1019,22 +998,22 @@ free_pages(ptr, index, info) |
|
|
struct pginfo *info; |
|
|
struct pginfo *info; |
|
|
{ |
|
|
{ |
|
|
int i; |
|
|
int i; |
|
|
struct pgfree *pf,*pt=0; |
|
|
|
|
|
|
|
|
struct pgfree *pf, *pt=0; |
|
|
u_long l; |
|
|
u_long l; |
|
|
void *tail; |
|
|
void *tail; |
|
|
|
|
|
|
|
|
if (info == MALLOC_FREE) { |
|
|
if (info == MALLOC_FREE) { |
|
|
wrtwarning("free(): already free page.\n"); |
|
|
|
|
|
|
|
|
wrtwarning("page is already free.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (info != MALLOC_FIRST) { |
|
|
if (info != MALLOC_FIRST) { |
|
|
wrtwarning("free(): freeing wrong page.\n"); |
|
|
|
|
|
|
|
|
wrtwarning("pointer to wrong page.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if ((u_long)ptr & malloc_pagemask) { |
|
|
if ((u_long)ptr & malloc_pagemask) { |
|
|
wrtwarning("free(): modified page pointer.\n"); |
|
|
|
|
|
|
|
|
wrtwarning("modified (page-) pointer.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1045,11 +1024,16 @@ free_pages(ptr, index, info) |
|
|
|
|
|
|
|
|
l = i << malloc_pageshift; |
|
|
l = i << malloc_pageshift; |
|
|
|
|
|
|
|
|
tail = (char *)ptr + l; |
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__ |
|
|
|
|
|
if (malloc_hint) |
|
|
|
|
|
madvise(ptr, l, MADV_FREE); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
tail = (char *)ptr+l; |
|
|
|
|
|
|
|
|
/* add to free-list */ |
|
|
/* add to free-list */ |
|
|
if (!px) |
|
|
if (!px) |
|
|
px = malloc(sizeof *pt); /* This cannot fail... */ |
|
|
|
|
|
|
|
|
px = imalloc(sizeof *pt); /* This cannot fail... */ |
|
|
px->page = ptr; |
|
|
px->page = ptr; |
|
|
px->end = tail; |
|
|
px->end = tail; |
|
|
px->size = l; |
|
|
px->size = l; |
|
@ -1065,7 +1049,7 @@ free_pages(ptr, index, info) |
|
|
} else { |
|
|
} else { |
|
|
|
|
|
|
|
|
/* Find the right spot, leave pf pointing to the modified entry. */ |
|
|
/* Find the right spot, leave pf pointing to the modified entry. */ |
|
|
tail = (char *)ptr + l; |
|
|
|
|
|
|
|
|
tail = (char *)ptr+l; |
|
|
|
|
|
|
|
|
for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next) |
|
|
for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next) |
|
|
; /* Race ahead here */ |
|
|
; /* Race ahead here */ |
|
@ -1103,7 +1087,7 @@ free_pages(ptr, index, info) |
|
|
pf = px; |
|
|
pf = px; |
|
|
px = 0; |
|
|
px = 0; |
|
|
} else { |
|
|
} else { |
|
|
wrterror("messed up free list"); |
|
|
|
|
|
|
|
|
wrterror("freelist is destroyed.\n"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1132,7 +1116,7 @@ free_pages(ptr, index, info) |
|
|
/* XXX: We could realloc/shrink the pagedir here I guess. */ |
|
|
/* XXX: We could realloc/shrink the pagedir here I guess. */ |
|
|
} |
|
|
} |
|
|
if (pt) |
|
|
if (pt) |
|
|
free(pt); |
|
|
|
|
|
|
|
|
ifree(pt); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
@ -1154,16 +1138,16 @@ free_bytes(ptr, index, info) |
|
|
i = ((u_long)ptr & malloc_pagemask) >> info->shift; |
|
|
i = ((u_long)ptr & malloc_pagemask) >> info->shift; |
|
|
|
|
|
|
|
|
if (((u_long)ptr & (info->size-1))) { |
|
|
if (((u_long)ptr & (info->size-1))) { |
|
|
wrtwarning("free(): modified pointer.\n"); |
|
|
|
|
|
|
|
|
wrtwarning("modified (chunk-) pointer.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (tst_bit(info,i)) { |
|
|
|
|
|
wrtwarning("free(): already free chunk.\n"); |
|
|
|
|
|
|
|
|
if (tst_bit(info, i)) { |
|
|
|
|
|
wrtwarning("chunk is already free.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
set_bit(info,i); |
|
|
|
|
|
|
|
|
set_bit(info, i); |
|
|
info->free++; |
|
|
info->free++; |
|
|
|
|
|
|
|
|
mp = page_dir + info->shift; |
|
|
mp = page_dir + info->shift; |
|
@ -1198,12 +1182,12 @@ free_bytes(ptr, index, info) |
|
|
page_dir[ptr2index(info->page)] = MALLOC_FIRST; |
|
|
page_dir[ptr2index(info->page)] = MALLOC_FIRST; |
|
|
vp = info->page; /* Order is important ! */ |
|
|
vp = info->page; /* Order is important ! */ |
|
|
if(vp != (void*)info) |
|
|
if(vp != (void*)info) |
|
|
free(info); |
|
|
|
|
|
free(vp); |
|
|
|
|
|
|
|
|
ifree(info); |
|
|
|
|
|
ifree(vp); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
free(ptr) |
|
|
|
|
|
|
|
|
static void |
|
|
|
|
|
ifree(ptr) |
|
|
void *ptr; |
|
|
void *ptr; |
|
|
{ |
|
|
{ |
|
|
struct pginfo *info; |
|
|
struct pginfo *info; |
|
@ -1217,7 +1201,7 @@ free(ptr) |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
if (!initialized) { |
|
|
if (!initialized) { |
|
|
wrtwarning("free(): malloc() never got called.\n"); |
|
|
|
|
|
|
|
|
wrtwarning("malloc() has never been called.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1225,35 +1209,102 @@ free(ptr) |
|
|
if (suicide) |
|
|
if (suicide) |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_block(&status); |
|
|
|
|
|
#endif |
|
|
|
|
|
index = ptr2index(ptr); |
|
|
index = ptr2index(ptr); |
|
|
|
|
|
|
|
|
if (index < malloc_pageshift) { |
|
|
if (index < malloc_pageshift) { |
|
|
wrtwarning("free(): junk pointer (too low)\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
wrtwarning("junk pointer, too low to make sense.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (index > last_index) { |
|
|
if (index > last_index) { |
|
|
wrtwarning("free(): junk pointer (too high)\n"); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
wrtwarning("junk pointer, too high to make sense.\n"); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
info = page_dir[index]; |
|
|
info = page_dir[index]; |
|
|
|
|
|
|
|
|
if (info < MALLOC_MAGIC) |
|
|
if (info < MALLOC_MAGIC) |
|
|
free_pages(ptr,index,info); |
|
|
|
|
|
|
|
|
free_pages(ptr, index, info); |
|
|
else |
|
|
else |
|
|
free_bytes(ptr,index,info); |
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
_thread_kern_sig_unblock(status); |
|
|
|
|
|
|
|
|
free_bytes(ptr, index, info); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* These are the public exported interface routines. |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
#ifdef _THREAD_SAFE |
|
|
|
|
|
#include <pthread.h> |
|
|
|
|
|
#include "pthread_private.h" |
|
|
|
|
|
static int malloc_lock; |
|
|
|
|
|
#define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock); |
|
|
|
|
|
#define THREAD_UNLOCK() _thread_kern_sig_unblock(&malloc_lock); |
|
|
|
|
|
#else |
|
|
|
|
|
#define THREAD_LOCK() |
|
|
|
|
|
#define THREAD_UNLOCK() |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
static int malloc_active; |
|
|
|
|
|
|
|
|
|
|
|
void * |
|
|
|
|
|
malloc(size_t size) |
|
|
|
|
|
{ |
|
|
|
|
|
register void *r; |
|
|
|
|
|
|
|
|
|
|
|
malloc_func = "malloc():"; |
|
|
|
|
|
THREAD_LOCK(); |
|
|
|
|
|
if (malloc_active++) { |
|
|
|
|
|
wrtwarning("recursive call.\n"); |
|
|
|
|
|
malloc_active--; |
|
|
|
|
|
return (0); |
|
|
|
|
|
} |
|
|
|
|
|
r = imalloc(size); |
|
|
|
|
|
UTRACE(0, size, r); |
|
|
|
|
|
malloc_active--; |
|
|
|
|
|
THREAD_UNLOCK(); |
|
|
|
|
|
return (r); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
free(void *ptr) |
|
|
|
|
|
{ |
|
|
|
|
|
malloc_func = "free():"; |
|
|
|
|
|
THREAD_LOCK(); |
|
|
|
|
|
if (malloc_active++) { |
|
|
|
|
|
wrtwarning("recursive call.\n"); |
|
|
|
|
|
malloc_active--; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
ifree(ptr); |
|
|
|
|
|
UTRACE(ptr, 0, 0); |
|
|
|
|
|
malloc_active--; |
|
|
|
|
|
THREAD_UNLOCK(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void * |
|
|
|
|
|
realloc(void *ptr, size_t size) |
|
|
|
|
|
{ |
|
|
|
|
|
register void *r; |
|
|
|
|
|
|
|
|
|
|
|
malloc_func = "realloc():"; |
|
|
|
|
|
THREAD_LOCK(); |
|
|
|
|
|
if (malloc_active++) { |
|
|
|
|
|
wrtwarning("recursive call.\n"); |
|
|
|
|
|
malloc_active--; |
|
|
|
|
|
return (0); |
|
|
|
|
|
} |
|
|
|
|
|
if (!ptr) { |
|
|
|
|
|
r = imalloc(size); |
|
|
|
|
|
} else if (ptr && !size) { |
|
|
|
|
|
ifree(ptr); |
|
|
|
|
|
r = 0; |
|
|
|
|
|
} else { |
|
|
|
|
|
r = irealloc(ptr, size); |
|
|
|
|
|
} |
|
|
|
|
|
UTRACE(ptr, size, r); |
|
|
|
|
|
malloc_active--; |
|
|
|
|
|
THREAD_UNLOCK(); |
|
|
|
|
|
return (r); |
|
|
|
|
|
} |