@ -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 . m alloc_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 . m alloc_stats )
if ( malloc_stats )
malloc_dump ( STDERR_FILENO ) ;
malloc_dump ( STDERR_FILENO ) ;
# endif /* MALLOC_STATS */
# endif /* MALLOC_STATS */
/ / malloc_active - - ;
/ / malloc_active - - ;
if ( mopts . m alloc_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 . m alloc_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 . m alloc_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 . m alloc_cache ; i + + ) {
r = & d - > free_regions [ ( i + offset ) & ( mopts . m alloc_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 . m alloc_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 . m alloc_hint )
if ( malloc_hint )
madvise ( p , sz , MADV_FREE ) ;
madvise ( p , sz , MADV_FREE ) ;
if ( mopts . m alloc_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 . m alloc_cache )
if ( i = = malloc_cache )
wrterror ( " malloc free slot lost " ) ;
wrterror ( " malloc free slot lost " ) ;
if ( d - > free_regions_size > mopts . m alloc_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 . m alloc_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 . m alloc_cache ; i + + ) {
r = & d - > free_regions [ ( i + offset ) & ( mopts . m alloc_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 . m alloc_freeprot )
if ( malloc_freeprot )
mprotect ( p , sz , PROT_READ | PROT_WRITE ) ;
mprotect ( p , sz , PROT_READ | PROT_WRITE ) ;
if ( mopts . m alloc_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 . m alloc_freeprot )
if ( malloc_freeprot )
mprotect ( p , sz , PROT_READ | PROT_WRITE ) ;
mprotect ( p , sz , PROT_READ | PROT_WRITE ) ;
if ( mopts . m alloc_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 . m alloc_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 . m alloc_cache < < = 1 ;
if ( mopts . m alloc_cache > MALLOC_MAXCACHE )
mopts . m alloc_cache = MALLOC_MAXCACHE ;
malloc_cache < < = 1 ;
if ( malloc_cache > MALLOC_MAXCACHE )
malloc_cache = MALLOC_MAXCACHE ;
break ;
break ;
case ' < ' :
case ' < ' :
mopts . m alloc_cache > > = 1 ;
malloc_cache > > = 1 ;
break ;
break ;
case ' a ' :
case ' a ' :
mopts . m alloc_abort = 0 ;
malloc_abort = 0 ;
break ;
break ;
case ' A ' :
case ' A ' :
mopts . m alloc_abort = 1 ;
malloc_abort = 1 ;
break ;
break ;
# ifdef MALLOC_STATS
# ifdef MALLOC_STATS
case ' d ' :
case ' d ' :
mopts . m alloc_stats = 0 ;
malloc_stats = 0 ;
break ;
break ;
case ' D ' :
case ' D ' :
mopts . m alloc_stats = 1 ;
malloc_stats = 1 ;
break ;
break ;
# endif /* MALLOC_STATS */
# endif /* MALLOC_STATS */
case ' f ' :
case ' f ' :
mopts . m alloc_freeprot = 0 ;
malloc_freeprot = 0 ;
break ;
break ;
case ' F ' :
case ' F ' :
mopts . m alloc_freeprot = 1 ;
malloc_freeprot = 1 ;
break ;
break ;
case ' g ' :
case ' g ' :
mopts . m alloc_guard = 0 ;
malloc_guard = 0 ;
break ;
break ;
case ' G ' :
case ' G ' :
mopts . m alloc_guard = MALLOC_PAGESIZE ;
malloc_guard = MALLOC_PAGESIZE ;
break ;
break ;
case ' h ' :
case ' h ' :
mopts . m alloc_hint = 0 ;
malloc_hint = 0 ;
break ;
break ;
case ' H ' :
case ' H ' :
mopts . m alloc_hint = 1 ;
malloc_hint = 1 ;
break ;
break ;
case ' j ' :
case ' j ' :
mopts . m alloc_junk = 0 ;
malloc_junk = 0 ;
break ;
break ;
case ' J ' :
case ' J ' :
mopts . m alloc_junk = 1 ;
malloc_junk = 1 ;
break ;
break ;
case ' n ' :
case ' n ' :
case ' N ' :
case ' N ' :
break ;
break ;
case ' p ' :
case ' p ' :
mopts . m alloc_move = 0 ;
malloc_move = 0 ;
break ;
break ;
case ' P ' :
case ' P ' :
mopts . m alloc_move = 1 ;
malloc_move = 1 ;
break ;
break ;
case ' r ' :
case ' r ' :
mopts . m alloc_realloc = 0 ;
malloc_realloc = 0 ;
break ;
break ;
case ' R ' :
case ' R ' :
mopts . m alloc_realloc = 1 ;
malloc_realloc = 1 ;
break ;
break ;
case ' x ' :
case ' x ' :
mopts . m alloc_xmalloc = 0 ;
malloc_xmalloc = 0 ;
break ;
break ;
case ' X ' :
case ' X ' :
mopts . m alloc_xmalloc = 1 ;
malloc_xmalloc = 1 ;
break ;
break ;
case ' z ' :
case ' z ' :
mopts . m alloc_zero = 0 ;
malloc_zero = 0 ;
break ;
break ;
case ' Z ' :
case ' Z ' :
mopts . m alloc_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 . m alloc_zero )
mopts . m alloc_junk = 1 ;
if ( malloc_zero )
malloc_junk = 1 ;
# ifdef MALLOC_STATS
# ifdef MALLOC_STATS
if ( mopts . m alloc_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 . m alloc_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 . m alloc_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 . m alloc_guard - MALLOC_PAGESIZE ) {
if ( sz > = SIZE_MAX - malloc_guard - MALLOC_PAGESIZE ) {
errno = ENOMEM ;
errno = ENOMEM ;
return NULL ;
return NULL ;
}
}
sz + = mopts . m alloc_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 . m alloc_guard ) {
if ( mprotect ( ( char * ) p + psz - mopts . m alloc_guard ,
mopts . m alloc_guard , PROT_NONE ) )
if ( malloc_guard ) {
if ( mprotect ( ( char * ) p + psz - malloc_guard ,
malloc_guard , PROT_NONE ) )
wrterror ( " mprotect " ) ;
wrterror ( " mprotect " ) ;
malloc_guarded + = mopts . m alloc_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 . m alloc_junk )
memset ( p , SOME_JUNK , psz - mopts . m alloc_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 . m alloc_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 . m alloc_junk )
memset ( p , 0 , sz - mopts . m alloc_guard ) ;
if ( zero_fill & & malloc_junk )
memset ( p , 0 , sz - malloc_guard ) ;
} else {
} else {
if ( mopts . m alloc_junk ) {
if ( malloc_junk ) {
if ( zero_fill )
if ( zero_fill )
memset ( p + sz - mopts . m alloc_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 . m alloc_zero ) ;
r = omalloc ( size , malloc_zero ) ;
malloc_active - - ;
malloc_active - - ;
_MALLOC_UNLOCK ( ) ;
_MALLOC_UNLOCK ( ) ;
if ( r = = NULL & & mopts . m alloc_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 . m alloc_guard ) &
MALLOC_MINSIZE - sz - malloc_guard ) &
~ ( MALLOC_MINSIZE - 1 ) ) ) {
~ ( MALLOC_MINSIZE - 1 ) ) ) {
}
}
# endif
# endif
p = r - > p ;
p = r - > p ;
}
}
if ( mopts . m alloc_guard ) {
if ( sz < mopts . m alloc_guard )
if ( malloc_guard ) {
if ( sz < malloc_guard )
wrterror ( " guard size " ) ;
wrterror ( " guard size " ) ;
if ( ! mopts . m alloc_freeprot ) {
if ( ! malloc_freeprot ) {
if ( mprotect ( ( char * ) p + PAGEROUND ( sz ) -
if ( mprotect ( ( char * ) p + PAGEROUND ( sz ) -
mopts . m alloc_guard , mopts . malloc_guard ,
malloc_guard , malloc_guard ,
PROT_READ | PROT_WRITE ) )
PROT_READ | PROT_WRITE ) )
wrterror ( " mprotect " ) ;
wrterror ( " mprotect " ) ;
}
}
malloc_guarded - = mopts . m alloc_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 . m alloc_junk & & sz > 0 )
if ( malloc_junk & & sz > 0 )
memset ( p , SOME_FREEJUNK , sz ) ;
memset ( p , SOME_FREEJUNK , sz ) ;
if ( ! mopts . m alloc_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 . m alloc_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 . m alloc_guard )
if ( oldsz < malloc_guard )
wrterror ( " guard size " ) ;
wrterror ( " guard size " ) ;
oldsz - = mopts . m alloc_guard ;
oldsz - = malloc_guard ;
}
}
gnewsz = newsz ;
gnewsz = newsz ;
if ( gnewsz > MALLOC_MAXCHUNK )
if ( gnewsz > MALLOC_MAXCHUNK )
gnewsz + = mopts . m alloc_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 . m alloc_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 . m alloc_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 . m alloc_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 . m alloc_junk )
if ( newsz > oldsz & & malloc_junk )
memset ( ( char * ) p + newsz , SOME_JUNK ,
memset ( ( char * ) p + newsz , SOME_JUNK ,
rnewsz - mopts . m alloc_guard - newsz ) ;
rnewsz - malloc_guard - newsz ) ;
r - > size = gnewsz ;
r - > size = gnewsz ;
return p ;
return p ;
}
}
}
}
if ( newsz < = oldsz & & newsz > oldsz / 2 & & ! mopts . m alloc_realloc ) {
if ( mopts . m alloc_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 . m alloc_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 . m alloc_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 . m alloc_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 . m alloc_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 ;
}
}