Browse Source

Latest changes from FreeBSD

OPENBSD_2_0
tholo 28 years ago
parent
commit
61617e17d2
2 changed files with 381 additions and 228 deletions
  1. +110
    -8
      src/lib/libc/stdlib/malloc.3
  2. +271
    -220
      src/lib/libc/stdlib/malloc.c

+ 110
- 8
src/lib/libc/stdlib/malloc.3 View File

@ -33,11 +33,11 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: malloc.3,v 1.3 1996/08/21 03:12:18 downsj Exp $
.\" $OpenBSD: malloc.3,v 1.4 1996/09/26 04:19:41 tholo Exp $
.\" .\"
.Dd June 4, 1993
.Dd August 27, 1996
.Dt MALLOC 3 .Dt MALLOC 3
.Os BSD 4
.Os OpenBSD
.Sh NAME .Sh NAME
.Nm malloc , .Nm malloc ,
.Nd general memory allocation function .Nd general memory allocation function
@ -58,6 +58,8 @@
.Fn cfree "void *ptr" .Fn cfree "void *ptr"
.Ft void * .Ft void *
.Fn realloc "void *ptr" "size_t size" .Fn realloc "void *ptr" "size_t size"
.Ft char *
.Va malloc_options
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Fn malloc .Fn malloc
@ -120,11 +122,13 @@ is zero and
.Fa ptr .Fa ptr
is not a null pointer, the object it points to is freed. is not a null pointer, the object it points to is freed.
.Pp .Pp
.Sh ENVIRONMENT
This malloc will check the environment for a variable called
.Em MALLOC_OPTIONS
and scan it for flags.
Malloc will first look for a symbolic link called
.Pa /etc/malloc.conf
and next check the environment for a variable called
.Ev MALLOC_OPTIONS
and finally for the global variable
.Va malloc_options
and scan them for flags in that order.
Flags are single letters, uppercase means on, lowercase means off. Flags are single letters, uppercase means on, lowercase means off.
.Bl -tag -width indent .Bl -tag -width indent
.It A .It A
@ -142,21 +146,42 @@ order to have any effect.
``junk'' fill some junk into the area allocated. ``junk'' fill some junk into the area allocated.
Currently junk is bytes of 0xd0, this is pronounced ``Duh'' :-) Currently junk is bytes of 0xd0, this is pronounced ``Duh'' :-)
.It H
``hint'' pass a hint to the kernel about pages we don't use. If the
machine is paging a lot this may help a bit.
.It R .It R
``realloc'' always reallocate when ``realloc'' always reallocate when
.Fn realloc .Fn realloc
is called, even if the initial allocation was big enough. is called, even if the initial allocation was big enough.
This can substantially aid in compacting memory. This can substantially aid in compacting memory.
.It U
``utrace'' generate entries for ktrace(1) for all operations.
Consult the source for this one.
.It Z .It Z
``zero'' fill some junk into the area allocated (see ``J''), ``zero'' fill some junk into the area allocated (see ``J''),
except for the exact length the user asked for, which is zeroed. except for the exact length the user asked for, which is zeroed.
.It <
``Half the cache size'' Reduce the size of the cache by a factor of two.
.It >
``Double the cache size'' Double the size of the cache by a factor of two.
.El .El
.Pp .Pp
So to set a systemwide reduction of cache size and coredumps on problems
one would:
.Li ln -s 'A<' /etc/malloc.conf
.Pp
The ``J'' and ``Z'' is mostly for testing and debugging, The ``J'' and ``Z'' is mostly for testing and debugging,
if a program changes behavior if either of these options are used, if a program changes behavior if either of these options are used,
it is buggy. it is buggy.
.Pp
The default cache size is 16 pages.
.Sh ENVIRONMENT
See above.
.Sh RETURN VALUES .Sh RETURN VALUES
The The
.Fn malloc .Fn malloc
@ -172,12 +197,89 @@ The
.Fn realloc .Fn realloc
function returns either a null pointer or a pointer function returns either a null pointer or a pointer
to the possibly moved allocated space. to the possibly moved allocated space.
.Sh MESSAGES
If
.Fn malloc ,
.Fn free
or
.Fn realloc
detects an error or warning condition,
a message will be printed to filedescriptor
2 (not using stdio).
Errors will always result in the process being
.Xr abort 2 'ed,
If the ``A'' option has been specified, also warnings will
.Xr abort 2
the process.
.Pp
Here is a brief description of the error messages and what they mean:
.Pp
``(ES): mumble mumble mumble'':
malloc have been compiled with -DEXTRA_SANITY and something looks
fishy in there. Consult sources and or wizards.
.Pp
``allocation failed''
if the ``A'' option is specified it is an error for
.Fn malloc
or
.Fn realloc
to return NULL.
.Pp
``mmap(2) failed, check limits.''
This is a rather weird condition that is most likely to mean that
the system is seriously overloaded or that your ulimits are sick.
.Pp
``freelist is destroyed.''
mallocs internal freelist has been stomped on.
.Pp
Here is a brief description of the warning messages and what they mean:
.Pp
``chunk/page is already free.''
A pointer to a free chunk is attempted freed again.
.Pp
``junk pointer, too high to make sense.''
The pointer doesn't make sense. It's above the area of memory that
malloc knows something about.
This could be a pointer from some
.Xr mmap 2 'ed
memory.
.Pp
``junk pointer, too low to make sense.''
The pointer doesn't make sense. It's below the area of memory that
malloc knows something about.
This pointer probably came from your data or bss segments.
.Pp
``malloc() has never been called.''
Nothing has ever been allocated, yet something is being freed or
realloc'ed.
.Pp
``modified (chunk-/page-) pointer.''
The pointer passed to free or realloc has been modified.
.Pp
``pointer to wrong page.''
The pointer that malloc is trying to free is not pointing to
a sensible page.
.Pp
``recursive call.''
You have tried to call recursively into these functions.
I can only imagine this as happening if you call one of these
functions from a signal function, which happens to be called
while you're already in here.
Well, sorry to say: that's not supported.
If this is a problem for you I'd like to hear about it. It
would be possible to add a sigblock() around this package,
but it would have a performance penalty that is not acceptable
as the default.
.Pp
``unknown char in MALLOC_OPTIONS''
we found something we didn't understand.
.Sh SEE ALSO .Sh SEE ALSO
.Xr brk 2 , .Xr brk 2 ,
.Xr alloca 3 , .Xr alloca 3 ,
.Xr calloc 3 , .Xr calloc 3 ,
.Xr getpagesize 3 , .Xr getpagesize 3 ,
.Xr memory 3 .Xr memory 3
.Pa /usr/share/doc/papers/malloc.ascii.gz
.Sh STANDARDS .Sh STANDARDS
The The
.Fn malloc .Fn malloc


+ 271
- 220
src/lib/libc/stdlib/malloc.c View File

@ -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);
}

Loading…
Cancel
Save