1999-04-08 02:10:10 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2008-12-31 19:15:49 +08:00
| Copyright ( c ) 1998 - 2009 Zend Technologies Ltd . ( http : //www.zend.com) |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2001-12-11 23:16:21 +08:00
| This source file is subject to version 2.00 of the Zend license , |
2006-07-18 17:06:33 +08:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-11 04:04:29 +08:00
| available through the world - wide - web at the following url : |
2001-12-11 23:16:21 +08:00
| http : //www.zend.com/license/2_00.txt. |
1999-07-16 22:58:16 +08:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ zend . com so we can mail you a copy immediately . |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Andi Gutmans < andi @ zend . com > |
| Zeev Suraski < zeev @ zend . com > |
2007-02-17 07:49:48 +08:00
| Dmitry Stogov < dmitry @ zend . com > |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2003-02-01 09:49:15 +08:00
/* $Id$ */
1999-04-08 02:10:10 +08:00
# include "zend.h"
# include "zend_alloc.h"
# include "zend_globals.h"
2006-07-18 17:06:33 +08:00
# include "zend_operators.h"
1999-09-07 00:14:08 +08:00
# ifdef HAVE_SIGNAL_H
# include <signal.h>
1999-07-09 19:19:38 +08:00
# endif
1999-09-07 00:14:08 +08:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
1999-07-09 19:19:38 +08:00
# endif
1999-04-08 02:10:10 +08:00
2006-12-18 19:39:19 +08:00
# ifdef ZEND_WIN32
# include <wincrypt.h>
# include <process.h>
# endif
2006-12-15 21:25:26 +08:00
# ifndef ZEND_MM_HEAP_PROTECTION
# define ZEND_MM_HEAP_PROTECTION ZEND_DEBUG
# endif
# ifndef ZEND_MM_SAFE_UNLINKING
# define ZEND_MM_SAFE_UNLINKING 1
# endif
# ifndef ZEND_MM_COOKIES
2007-02-01 23:08:10 +08:00
# define ZEND_MM_COOKIES ZEND_DEBUG
2006-12-15 21:25:26 +08:00
# endif
2007-04-16 16:09:56 +08:00
# ifdef _WIN64
# define PTR_FMT "0x%0.16I64x"
/*
# elif sizeof(long) == 8
# define PTR_FMT "0x%0.16lx"
*/
# else
# define PTR_FMT "0x%0.8lx"
# endif
2006-07-18 17:06:33 +08:00
# if ZEND_DEBUG
void zend_debug_alloc_output ( char * format , . . . )
{
char output_buf [ 256 ] ;
va_list args ;
va_start ( args , format ) ;
vsprintf ( output_buf , format , args ) ;
va_end ( args ) ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
# ifdef ZEND_WIN32
OutputDebugString ( output_buf ) ;
2002-06-24 21:41:26 +08:00
# else
2006-07-18 17:06:33 +08:00
fprintf ( stderr , " %s " , output_buf ) ;
# endif
}
2002-06-24 21:41:26 +08:00
# endif
1999-11-27 08:04:36 +08:00
2006-12-18 16:59:40 +08:00
# if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
2006-12-15 21:25:26 +08:00
static void zend_mm_panic ( const char * message ) __attribute__ ( ( noreturn ) ) ;
# endif
2006-07-18 17:06:33 +08:00
static void zend_mm_panic ( const char * message )
{
fprintf ( stderr , " %s \n " , message ) ;
# if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID)
kill ( getpid ( ) , SIGSEGV ) ;
# endif
2007-03-20 14:46:48 +08:00
exit ( 1 ) ;
2006-07-18 17:06:33 +08:00
}
/*******************/
/* Storage Manager */
/*******************/
# ifdef ZEND_WIN32
# define HAVE_MEM_WIN32 /* use VirtualAlloc() to allocate memory */
# endif
# define HAVE_MEM_MALLOC /* use malloc() to allocate segments */
# include <sys/types.h>
# include <sys/stat.h>
# if HAVE_LIMITS_H
# include <limits.h>
# endif
# include <fcntl.h>
# include <errno.h>
# if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
2007-03-20 14:46:48 +08:00
# ifdef HAVE_MREMAP
2009-03-20 19:23:00 +08:00
# ifndef _GNU_SOURCE
2007-03-20 14:46:48 +08:00
# define _GNU_SOURCE
2009-03-20 19:23:00 +08:00
# endif
# ifndef __USE_GNU
2007-03-20 14:46:48 +08:00
# define __USE_GNU
2009-03-20 19:23:00 +08:00
# endif
2007-03-20 14:46:48 +08:00
# endif
2006-07-18 17:06:33 +08:00
# include <sys / mman.h>
# ifndef MAP_ANON
# ifdef MAP_ANONYMOUS
# define MAP_ANON MAP_ANONYMOUS
# endif
# endif
# ifndef MREMAP_MAYMOVE
# define MREMAP_MAYMOVE 0
# endif
# ifndef MAP_FAILED
# define MAP_FAILED ((void*)-1)
# endif
# endif
static zend_mm_storage * zend_mm_mem_dummy_init ( void * params )
{
return malloc ( sizeof ( zend_mm_storage ) ) ;
}
static void zend_mm_mem_dummy_dtor ( zend_mm_storage * storage )
{
free ( storage ) ;
}
2007-09-29 18:37:29 +08:00
static void zend_mm_mem_dummy_compact ( zend_mm_storage * storage )
{
}
2006-07-18 17:06:33 +08:00
# if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
static zend_mm_segment * zend_mm_mem_mmap_realloc ( zend_mm_storage * storage , zend_mm_segment * segment , size_t size )
{
2006-07-18 23:41:58 +08:00
zend_mm_segment * ret ;
2006-07-18 17:06:33 +08:00
# ifdef HAVE_MREMAP
2009-04-02 00:55:47 +08:00
# if defined(__NetBSD__)
/* NetBSD 5 supports mremap but takes an extra newp argument */
ret = ( zend_mm_segment * ) mremap ( segment , segment - > size , segment , size , MREMAP_MAYMOVE ) ;
# else
2006-07-18 23:41:58 +08:00
ret = ( zend_mm_segment * ) mremap ( segment , segment - > size , size , MREMAP_MAYMOVE ) ;
2009-04-02 00:55:47 +08:00
# endif
2006-07-18 17:06:33 +08:00
if ( ret = = MAP_FAILED ) {
# endif
ret = storage - > handlers - > _alloc ( storage , size ) ;
if ( ret ) {
memcpy ( ret , segment , size > segment - > size ? segment - > size : size ) ;
storage - > handlers - > _free ( storage , segment ) ;
}
# ifdef HAVE_MREMAP
}
# endif
return ret ;
}
static void zend_mm_mem_mmap_free ( zend_mm_storage * storage , zend_mm_segment * segment )
{
2009-01-25 22:03:09 +08:00
munmap ( ( void * ) segment , segment - > size ) ;
2006-07-18 17:06:33 +08:00
}
# endif
# ifdef HAVE_MEM_MMAP_ANON
static zend_mm_segment * zend_mm_mem_mmap_anon_alloc ( zend_mm_storage * storage , size_t size )
{
zend_mm_segment * ret = ( zend_mm_segment * ) mmap ( NULL , size , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANON , - 1 , 0 ) ;
if ( ret = = MAP_FAILED ) {
ret = NULL ;
}
return ret ;
}
2007-09-29 18:37:29 +08:00
# define ZEND_MM_MEM_MMAP_ANON_DSC {"mmap_anon", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_anon_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
2006-07-18 17:06:33 +08:00
# endif
# ifdef HAVE_MEM_MMAP_ZERO
static int zend_mm_dev_zero_fd = - 1 ;
static zend_mm_storage * zend_mm_mem_mmap_zero_init ( void * params )
{
if ( zend_mm_dev_zero_fd ! = - 1 ) {
zend_mm_dev_zero_fd = open ( " /dev/zero " , O_RDWR , S_IRUSR | S_IWUSR ) ;
}
if ( zend_mm_dev_zero_fd > = 0 ) {
return malloc ( sizeof ( zend_mm_storage ) ) ;
} else {
return NULL ;
}
}
static void zend_mm_mem_mmap_zero_dtor ( zend_mm_storage * storage )
{
close ( zend_mm_dev_zero_fd ) ;
free ( storage ) ;
}
static zend_mm_segment * zend_mm_mem_mmap_zero_alloc ( zend_mm_storage * storage , size_t size )
{
zend_mm_segment * ret = ( zend_mm_segment * ) mmap ( NULL , size , PROT_READ | PROT_WRITE , MAP_PRIVATE , zend_mm_dev_zero_fd , 0 ) ;
if ( ret = = MAP_FAILED ) {
ret = NULL ;
}
return ret ;
}
2007-09-29 18:37:29 +08:00
# define ZEND_MM_MEM_MMAP_ZERO_DSC {"mmap_zero", zend_mm_mem_mmap_zero_init, zend_mm_mem_mmap_zero_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_zero_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
2006-07-18 17:06:33 +08:00
# endif
# ifdef HAVE_MEM_WIN32
2006-11-10 18:44:40 +08:00
static zend_mm_storage * zend_mm_mem_win32_init ( void * params )
{
HANDLE heap = HeapCreate ( HEAP_NO_SERIALIZE , 0 , 0 ) ;
zend_mm_storage * storage ;
2006-12-15 21:25:26 +08:00
2006-11-10 18:44:40 +08:00
if ( heap = = NULL ) {
return NULL ;
}
storage = ( zend_mm_storage * ) malloc ( sizeof ( zend_mm_storage ) ) ;
storage - > data = ( void * ) heap ;
return storage ;
}
static void zend_mm_mem_win32_dtor ( zend_mm_storage * storage )
{
HeapDestroy ( ( HANDLE ) storage - > data ) ;
free ( storage ) ;
}
2007-09-29 18:37:29 +08:00
static void zend_mm_mem_win32_compact ( zend_mm_storage * storage )
{
HeapDestroy ( ( HANDLE ) storage - > data ) ;
storage - > data = ( void * ) HeapCreate ( HEAP_NO_SERIALIZE , 0 , 0 ) ;
}
2006-07-18 17:06:33 +08:00
static zend_mm_segment * zend_mm_mem_win32_alloc ( zend_mm_storage * storage , size_t size )
{
2006-11-10 18:44:40 +08:00
return ( zend_mm_segment * ) HeapAlloc ( ( HANDLE ) storage - > data , HEAP_NO_SERIALIZE , size ) ;
2006-07-18 17:06:33 +08:00
}
static void zend_mm_mem_win32_free ( zend_mm_storage * storage , zend_mm_segment * segment )
{
2006-11-10 18:44:40 +08:00
HeapFree ( ( HANDLE ) storage - > data , HEAP_NO_SERIALIZE , segment ) ;
2006-07-18 17:06:33 +08:00
}
static zend_mm_segment * zend_mm_mem_win32_realloc ( zend_mm_storage * storage , zend_mm_segment * segment , size_t size )
{
2006-11-10 18:44:40 +08:00
return ( zend_mm_segment * ) HeapReAlloc ( ( HANDLE ) storage - > data , HEAP_NO_SERIALIZE , segment , size ) ;
2006-07-18 17:06:33 +08:00
}
2007-09-29 18:37:29 +08:00
# define ZEND_MM_MEM_WIN32_DSC {"win32", zend_mm_mem_win32_init, zend_mm_mem_win32_dtor, zend_mm_mem_win32_compact, zend_mm_mem_win32_alloc, zend_mm_mem_win32_realloc, zend_mm_mem_win32_free}
2006-07-18 17:06:33 +08:00
# endif
# ifdef HAVE_MEM_MALLOC
static zend_mm_segment * zend_mm_mem_malloc_alloc ( zend_mm_storage * storage , size_t size )
{
return ( zend_mm_segment * ) malloc ( size ) ;
}
static zend_mm_segment * zend_mm_mem_malloc_realloc ( zend_mm_storage * storage , zend_mm_segment * ptr , size_t size )
{
return ( zend_mm_segment * ) realloc ( ptr , size ) ;
}
static void zend_mm_mem_malloc_free ( zend_mm_storage * storage , zend_mm_segment * ptr )
{
free ( ptr ) ;
}
2007-09-29 18:37:29 +08:00
# define ZEND_MM_MEM_MALLOC_DSC {"malloc", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_malloc_alloc, zend_mm_mem_malloc_realloc, zend_mm_mem_malloc_free}
2006-07-18 17:06:33 +08:00
# endif
static const zend_mm_mem_handlers mem_handlers [ ] = {
2006-11-10 18:44:40 +08:00
# ifdef HAVE_MEM_WIN32
ZEND_MM_MEM_WIN32_DSC ,
# endif
2006-07-18 17:06:33 +08:00
# ifdef HAVE_MEM_MALLOC
ZEND_MM_MEM_MALLOC_DSC ,
# endif
# ifdef HAVE_MEM_MMAP_ANON
ZEND_MM_MEM_MMAP_ANON_DSC ,
# endif
# ifdef HAVE_MEM_MMAP_ZERO
ZEND_MM_MEM_MMAP_ZERO_DSC ,
# endif
{ NULL , NULL , NULL , NULL , NULL , NULL }
} ;
# define ZEND_MM_STORAGE_DTOR() heap->storage->handlers->dtor(heap->storage)
# define ZEND_MM_STORAGE_ALLOC(size) heap->storage->handlers->_alloc(heap->storage, size)
# define ZEND_MM_STORAGE_REALLOC(ptr, size) heap->storage->handlers->_realloc(heap->storage, ptr, size)
# define ZEND_MM_STORAGE_FREE(ptr) heap->storage->handlers->_free(heap->storage, ptr)
/****************/
/* Heap Manager */
/****************/
2007-01-09 23:29:14 +08:00
# define MEM_BLOCK_VALID 0x7312F8DC
# define MEM_BLOCK_FREED 0x99954317
# define MEM_BLOCK_CACHED 0xFB8277DC
# define MEM_BLOCK_GUARD 0x2A8FCC84
# define MEM_BLOCK_LEAK 0x6C5E8F2D
2006-07-18 17:06:33 +08:00
/* mm block type */
typedef struct _zend_mm_block_info {
2006-12-15 21:25:26 +08:00
# if ZEND_MM_COOKIES
2007-04-09 23:38:58 +08:00
size_t _cookie ;
2006-12-15 21:25:26 +08:00
# endif
2006-12-16 01:03:42 +08:00
size_t _size ;
size_t _prev ;
2006-07-18 17:06:33 +08:00
} zend_mm_block_info ;
2006-12-15 21:25:26 +08:00
# if ZEND_DEBUG
2006-07-18 17:06:33 +08:00
typedef struct _zend_mm_debug_info {
char * filename ;
uint lineno ;
char * orig_filename ;
uint orig_lineno ;
size_t size ;
2006-12-15 21:25:26 +08:00
# if ZEND_MM_HEAP_PROTECTION
unsigned int start_magic ;
# endif
2006-07-18 17:06:33 +08:00
} zend_mm_debug_info ;
2006-12-15 21:25:26 +08:00
# elif ZEND_MM_HEAP_PROTECTION
typedef struct _zend_mm_debug_info {
size_t size ;
unsigned int start_magic ;
} zend_mm_debug_info ;
# endif
2006-07-18 17:06:33 +08:00
typedef struct _zend_mm_block {
zend_mm_block_info info ;
# if ZEND_DEBUG
2007-01-09 23:29:14 +08:00
unsigned int magic ;
2006-07-18 17:06:33 +08:00
# ifdef ZTS
THREAD_T thread_id ;
# endif
2006-12-15 21:25:26 +08:00
zend_mm_debug_info debug ;
# elif ZEND_MM_HEAP_PROTECTION
zend_mm_debug_info debug ;
2006-07-18 17:06:33 +08:00
# endif
} zend_mm_block ;
2007-03-20 14:46:48 +08:00
typedef struct _zend_mm_small_free_block {
zend_mm_block_info info ;
# if ZEND_DEBUG
unsigned int magic ;
# ifdef ZTS
THREAD_T thread_id ;
# endif
# endif
struct _zend_mm_free_block * prev_free_block ;
struct _zend_mm_free_block * next_free_block ;
} zend_mm_small_free_block ;
2006-07-18 17:06:33 +08:00
typedef struct _zend_mm_free_block {
zend_mm_block_info info ;
# if ZEND_DEBUG
2007-01-09 23:29:14 +08:00
unsigned int magic ;
2006-12-15 21:25:26 +08:00
# ifdef ZTS
THREAD_T thread_id ;
# endif
2006-07-18 17:06:33 +08:00
# endif
struct _zend_mm_free_block * prev_free_block ;
struct _zend_mm_free_block * next_free_block ;
2007-03-20 14:46:48 +08:00
struct _zend_mm_free_block * * parent ;
struct _zend_mm_free_block * child [ 2 ] ;
2006-07-18 17:06:33 +08:00
} zend_mm_free_block ;
2007-03-20 14:46:48 +08:00
# define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
2006-07-18 17:06:33 +08:00
2008-01-15 17:48:55 +08:00
# define ZEND_MM_CACHE 1
2008-01-24 20:21:32 +08:00
# define ZEND_MM_CACHE_SIZE (ZEND_MM_NUM_BUCKETS * 4 * 1024)
2007-03-20 14:46:48 +08:00
# ifndef ZEND_MM_CACHE_STAT
# define ZEND_MM_CACHE_STAT 0
# endif
2006-07-18 17:06:33 +08:00
struct _zend_mm_heap {
2007-03-20 14:46:48 +08:00
int use_zend_alloc ;
2007-11-06 20:06:05 +08:00
void * ( * _malloc ) ( size_t ) ;
void ( * _free ) ( void * ) ;
void * ( * _realloc ) ( void * , size_t ) ;
2007-03-20 14:46:48 +08:00
size_t free_bitmap ;
size_t large_free_bitmap ;
2006-07-18 17:06:33 +08:00
size_t block_size ;
2007-10-25 15:32:40 +08:00
size_t compact_size ;
2006-07-18 17:06:33 +08:00
zend_mm_segment * segments_list ;
zend_mm_storage * storage ;
2009-01-25 21:39:56 +08:00
size_t real_size ;
2006-07-25 21:40:05 +08:00
size_t real_peak ;
2009-01-25 21:39:56 +08:00
size_t limit ;
2006-07-25 21:40:05 +08:00
size_t size ;
size_t peak ;
2007-03-20 14:46:48 +08:00
size_t reserve_size ;
2006-12-05 00:20:02 +08:00
void * reserve ;
2007-03-20 14:46:48 +08:00
int overflow ;
int internal ;
2006-07-18 17:06:33 +08:00
# if ZEND_MM_CACHE
unsigned int cached ;
zend_mm_free_block * cache [ ZEND_MM_NUM_BUCKETS ] ;
# endif
2007-03-20 14:46:48 +08:00
zend_mm_free_block * free_buckets [ ZEND_MM_NUM_BUCKETS * 2 ] ;
zend_mm_free_block * large_free_buckets [ ZEND_MM_NUM_BUCKETS ] ;
zend_mm_free_block * rest_buckets [ 2 ] ;
# if ZEND_MM_CACHE_STAT
struct {
int count ;
int max_count ;
int hit ;
int miss ;
} cache_stat [ ZEND_MM_NUM_BUCKETS + 1 ] ;
# endif
2006-07-18 17:06:33 +08:00
} ;
2007-03-20 14:46:48 +08:00
# define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
( zend_mm_free_block * ) ( ( char * ) & heap - > free_buckets [ index * 2 ] + \
sizeof ( zend_mm_free_block * ) * 2 - \
sizeof ( zend_mm_small_free_block ) )
# define ZEND_MM_REST_BUCKET(heap) \
( zend_mm_free_block * ) ( ( char * ) & heap - > rest_buckets [ 0 ] + \
2009-01-25 21:39:56 +08:00
sizeof ( zend_mm_free_block * ) * 2 - \
sizeof ( zend_mm_small_free_block ) )
2006-12-15 21:25:26 +08:00
# if ZEND_MM_COOKIES
static unsigned int _zend_mm_cookie = 0 ;
# define ZEND_MM_COOKIE(block) \
2007-04-09 23:38:58 +08:00
( ( ( size_t ) ( block ) ) ^ _zend_mm_cookie )
2006-12-15 21:25:26 +08:00
# define ZEND_MM_SET_COOKIE(block) \
( block ) - > info . _cookie = ZEND_MM_COOKIE ( block )
# define ZEND_MM_CHECK_COOKIE(block) \
if ( UNEXPECTED ( ( block ) - > info . _cookie ! = ZEND_MM_COOKIE ( block ) ) ) { \
zend_mm_panic ( " zend_mm_heap corrupted " ) ; \
}
# else
# define ZEND_MM_SET_COOKIE(block)
# define ZEND_MM_CHECK_COOKIE(block)
# endif
2007-03-20 14:46:48 +08:00
/* Default memory segment size */
# define ZEND_MM_SEG_SIZE (256 * 1024)
2006-12-05 00:20:02 +08:00
/* Reserved space for error reporting in case of memory overflow */
2007-03-20 14:46:48 +08:00
# define ZEND_MM_RESERVE_SIZE (8*1024)
2006-12-05 00:20:02 +08:00
2007-04-09 23:38:58 +08:00
# ifdef _WIN64
# define ZEND_MM_LONG_CONST(x) (x##i64)
# else
# define ZEND_MM_LONG_CONST(x) (x##L)
# endif
# define ZEND_MM_TYPE_MASK ZEND_MM_LONG_CONST(0x3)
2006-07-18 17:06:33 +08:00
2007-04-09 23:38:58 +08:00
# define ZEND_MM_FREE_BLOCK ZEND_MM_LONG_CONST(0x0)
# define ZEND_MM_USED_BLOCK ZEND_MM_LONG_CONST(0x1)
# define ZEND_MM_GUARD_BLOCK ZEND_MM_LONG_CONST(0x3)
2006-07-18 17:06:33 +08:00
# define ZEND_MM_BLOCK(b, type, size) do { \
size_t _size = ( size ) ; \
( b ) - > info . _size = ( type ) | _size ; \
ZEND_MM_BLOCK_AT ( b , _size ) - > info . _prev = ( type ) | _size ; \
2006-12-15 21:25:26 +08:00
ZEND_MM_SET_COOKIE ( b ) ; \
2006-07-18 17:06:33 +08:00
} while ( 0 ) ;
# define ZEND_MM_LAST_BLOCK(b) do { \
( b ) - > info . _size = ZEND_MM_GUARD_BLOCK | ZEND_MM_ALIGNED_HEADER_SIZE ; \
ZEND_MM_SET_MAGIC ( b , MEM_BLOCK_GUARD ) ; \
} while ( 0 ) ;
# define ZEND_MM_BLOCK_SIZE(b) ((b)->info._size & ~ZEND_MM_TYPE_MASK)
# define ZEND_MM_IS_FREE_BLOCK(b) (!((b)->info._size & ZEND_MM_USED_BLOCK))
# define ZEND_MM_IS_USED_BLOCK(b) ((b)->info._size & ZEND_MM_USED_BLOCK)
# define ZEND_MM_IS_GUARD_BLOCK(b) (((b)->info._size & ZEND_MM_TYPE_MASK) == ZEND_MM_GUARD_BLOCK)
# define ZEND_MM_NEXT_BLOCK(b) ZEND_MM_BLOCK_AT(b, ZEND_MM_BLOCK_SIZE(b))
# define ZEND_MM_PREV_BLOCK(b) ZEND_MM_BLOCK_AT(b, -(int)((b)->info._prev & ~ZEND_MM_TYPE_MASK))
# define ZEND_MM_PREV_BLOCK_IS_FREE(b) (!((b)->info._prev & ZEND_MM_USED_BLOCK))
# define ZEND_MM_MARK_FIRST_BLOCK(b) ((b)->info._prev = ZEND_MM_GUARD_BLOCK)
# define ZEND_MM_IS_FIRST_BLOCK(b) ((b)->info._prev == ZEND_MM_GUARD_BLOCK)
/* optimized access */
# define ZEND_MM_FREE_BLOCK_SIZE(b) (b)->info._size
# ifndef ZEND_MM_ALIGNMENT
# define ZEND_MM_ALIGNMENT 8
# define ZEND_MM_ALIGNMENT_LOG2 3
2006-12-01 23:33:06 +08:00
# elif ZEND_MM_ALIGNMENT < 4
# undef ZEND_MM_ALIGNMENT
2006-12-02 03:41:57 +08:00
# undef ZEND_MM_ALIGNMENT_LOG2
2006-12-01 23:33:06 +08:00
# define ZEND_MM_ALIGNMENT 4
# define ZEND_MM_ALIGNMENT_LOG2 2
2001-08-03 15:06:05 +08:00
# endif
2006-07-18 17:06:33 +08:00
# define ZEND_MM_ALIGNMENT_MASK ~(ZEND_MM_ALIGNMENT-1)
/* Aligned header size */
# define ZEND_MM_ALIGNED_SIZE(size) ((size + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK)
# define ZEND_MM_ALIGNED_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block))
2007-03-20 14:46:48 +08:00
# define ZEND_MM_ALIGNED_FREE_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block))
2006-11-23 17:32:39 +08:00
# define ZEND_MM_MIN_ALLOC_BLOCK_SIZE ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE)
# define ZEND_MM_ALIGNED_MIN_HEADER_SIZE (ZEND_MM_MIN_ALLOC_BLOCK_SIZE>ZEND_MM_ALIGNED_FREE_HEADER_SIZE?ZEND_MM_MIN_ALLOC_BLOCK_SIZE:ZEND_MM_ALIGNED_FREE_HEADER_SIZE)
2006-07-18 17:06:33 +08:00
# define ZEND_MM_ALIGNED_SEGMENT_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_segment))
2006-12-25 20:16:33 +08:00
# define ZEND_MM_MIN_SIZE ((ZEND_MM_ALIGNED_MIN_HEADER_SIZE>(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE))?(ZEND_MM_ALIGNED_MIN_HEADER_SIZE-(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE)):0)
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
# define ZEND_MM_MAX_SMALL_SIZE ((ZEND_MM_NUM_BUCKETS<<ZEND_MM_ALIGNMENT_LOG2)+ZEND_MM_ALIGNED_MIN_HEADER_SIZE)
2006-07-18 17:06:33 +08:00
2006-12-25 20:16:33 +08:00
# define ZEND_MM_TRUE_SIZE(size) ((size<ZEND_MM_MIN_SIZE)?(ZEND_MM_ALIGNED_MIN_HEADER_SIZE):(ZEND_MM_ALIGNED_SIZE(size+ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE)))
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
# define ZEND_MM_BUCKET_INDEX(true_size) ((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))
2006-07-18 17:06:33 +08:00
# define ZEND_MM_SMALL_SIZE(true_size) (true_size < ZEND_MM_MAX_SMALL_SIZE)
/* Memory calculations */
# define ZEND_MM_BLOCK_AT(blk, offset) ((zend_mm_block *) (((char *) (blk))+(offset)))
# define ZEND_MM_DATA_OF(p) ((void *) (((char *) (p))+ZEND_MM_ALIGNED_HEADER_SIZE))
# define ZEND_MM_HEADER_OF(blk) ZEND_MM_BLOCK_AT(blk, -(int)ZEND_MM_ALIGNED_HEADER_SIZE)
/* Debug output */
1999-04-08 02:10:10 +08:00
# if ZEND_DEBUG
2006-07-18 17:06:33 +08:00
# ifdef ZTS
2006-12-15 21:25:26 +08:00
# define ZEND_MM_SET_THREAD_ID(block) \
( ( zend_mm_block * ) ( block ) ) - > thread_id = tsrm_thread_id ( )
2006-07-18 17:06:33 +08:00
# define ZEND_MM_BAD_THREAD_ID(block) ((block)->thread_id != tsrm_thread_id())
# else
2006-12-15 21:25:26 +08:00
# define ZEND_MM_SET_THREAD_ID(block)
2006-07-18 17:06:33 +08:00
# define ZEND_MM_BAD_THREAD_ID(block) 0
# endif
# define ZEND_MM_VALID_PTR(block) \
zend_mm_check_ptr ( heap , block , 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC )
# define ZEND_MM_SET_MAGIC(block, val) do { \
( block ) - > magic = ( val ) ; \
} while ( 0 )
# define ZEND_MM_CHECK_MAGIC(block, val) do { \
if ( ( block ) - > magic ! = ( val ) ) { \
2006-12-15 21:25:26 +08:00
zend_mm_panic ( " zend_mm_heap corrupted " ) ; \
2006-07-18 17:06:33 +08:00
} \
} while ( 0 )
2006-12-15 21:25:26 +08:00
# define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) do { \
( ( zend_mm_block * ) ( block ) ) - > debug . filename = __zend_filename ; \
( ( zend_mm_block * ) ( block ) ) - > debug . lineno = __zend_lineno ; \
( ( zend_mm_block * ) ( block ) ) - > debug . orig_filename = __zend_orig_filename ; \
( ( zend_mm_block * ) ( block ) ) - > debug . orig_lineno = __zend_orig_lineno ; \
ZEND_MM_SET_BLOCK_SIZE ( block , __size ) ; \
if ( set_valid ) { \
ZEND_MM_SET_MAGIC ( block , MEM_BLOCK_VALID ) ; \
} \
if ( set_thread ) { \
ZEND_MM_SET_THREAD_ID ( block ) ; \
} \
2006-07-18 17:06:33 +08:00
} while ( 0 )
1999-04-08 02:10:10 +08:00
# else
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
# define ZEND_MM_VALID_PTR(ptr) EXPECTED(ptr != NULL)
2006-07-18 17:06:33 +08:00
# define ZEND_MM_SET_MAGIC(block, val)
# define ZEND_MM_CHECK_MAGIC(block, val)
2006-12-15 21:25:26 +08:00
# define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) ZEND_MM_SET_BLOCK_SIZE(block, __size)
# endif
# if ZEND_MM_HEAP_PROTECTION
# define ZEND_MM_CHECK_PROTECTION(block) \
do { \
if ( ( block ) - > debug . start_magic ! = _mem_block_start_magic | | \
memcmp ( ZEND_MM_END_MAGIC_PTR ( block ) , & _mem_block_end_magic , END_MAGIC_SIZE ) ! = 0 ) { \
zend_mm_panic ( " zend_mm_heap corrupted " ) ; \
} \
} while ( 0 )
# define ZEND_MM_END_MAGIC_PTR(block) \
2007-02-20 02:29:31 +08:00
( ( ( char * ) ( ZEND_MM_DATA_OF ( block ) ) ) + ( ( zend_mm_block * ) ( block ) ) - > debug . size )
2006-12-15 21:25:26 +08:00
# define END_MAGIC_SIZE sizeof(unsigned int)
# define ZEND_MM_SET_BLOCK_SIZE(block, __size) do { \
2007-02-20 02:29:31 +08:00
char * p ; \
2006-12-15 21:25:26 +08:00
( ( zend_mm_block * ) ( block ) ) - > debug . size = ( __size ) ; \
p = ZEND_MM_END_MAGIC_PTR ( block ) ; \
( ( zend_mm_block * ) ( block ) ) - > debug . start_magic = _mem_block_start_magic ; \
memcpy ( p , & _mem_block_end_magic , END_MAGIC_SIZE ) ; \
} while ( 0 )
static unsigned int _mem_block_start_magic = 0 ;
static unsigned int _mem_block_end_magic = 0 ;
# else
# if ZEND_DEBUG
# define ZEND_MM_SET_BLOCK_SIZE(block, _size) \
( ( zend_mm_block * ) ( block ) ) - > debug . size = ( _size )
# else
# define ZEND_MM_SET_BLOCK_SIZE(block, _size)
# endif
# define ZEND_MM_CHECK_PROTECTION(block)
1999-04-08 02:10:10 +08:00
# define END_MAGIC_SIZE 0
2006-07-18 17:06:33 +08:00
1999-04-08 02:10:10 +08:00
# endif
2006-12-15 21:25:26 +08:00
# if ZEND_MM_SAFE_UNLINKING
# define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( ( block ) - > info . _size ! = ZEND_MM_BLOCK_AT ( block , ZEND_MM_FREE_BLOCK_SIZE ( block ) ) - > info . _prev ) | | \
2006-12-15 21:25:26 +08:00
UNEXPECTED ( ! UNEXPECTED ( ZEND_MM_IS_FIRST_BLOCK ( block ) ) & & \
UNEXPECTED ( ZEND_MM_PREV_BLOCK ( block ) - > info . _size ! = ( block ) - > info . _prev ) ) ) { \
zend_mm_panic ( " zend_mm_heap corrupted " ) ; \
}
2007-03-20 14:46:48 +08:00
# define ZEND_MM_CHECK_TREE(block) \
if ( UNEXPECTED ( * ( ( block ) - > parent ) ! = ( block ) ) ) { \
zend_mm_panic ( " zend_mm_heap corrupted " ) ; \
}
2006-12-15 21:25:26 +08:00
# else
# define ZEND_MM_CHECK_BLOCK_LINKAGE(block)
2007-03-20 14:46:48 +08:00
# define ZEND_MM_CHECK_TREE(block)
2006-12-15 21:25:26 +08:00
# endif
2007-03-20 14:46:48 +08:00
# define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)
2006-12-15 21:25:26 +08:00
2007-03-20 14:46:48 +08:00
static void * _zend_mm_alloc_int ( zend_mm_heap * heap , size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC ) ZEND_ATTRIBUTE_MALLOC ;
static void _zend_mm_free_int ( zend_mm_heap * heap , void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC ) ;
static void * _zend_mm_realloc_int ( zend_mm_heap * heap , void * p , size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC ) ;
2006-12-15 21:25:26 +08:00
2007-03-20 14:46:48 +08:00
static inline unsigned int zend_mm_high_bit ( size_t _size )
{
# if defined(__GNUC__) && defined(i386)
2007-12-20 20:58:46 +08:00
unsigned int n ;
2007-03-20 14:46:48 +08:00
__asm__ ( " bsrl %1,%0 \n \t " : " =r " ( n ) : " rm " ( _size ) ) ;
return n ;
2007-12-20 20:58:46 +08:00
# elif defined(__GNUC__) && defined(__x86_64__)
unsigned long n ;
__asm__ ( " bsrq %1,%0 \n \t " : " =r " ( n ) : " rm " ( _size ) ) ;
return ( unsigned int ) n ;
2007-03-20 14:46:48 +08:00
# elif defined(_MSC_VER) && defined(_M_IX86)
__asm {
bsr eax , _size
}
# else
unsigned int n = 0 ;
while ( _size ! = 0 ) {
_size = _size > > 1 ;
n + + ;
}
return n - 1 ;
# endif
}
static inline unsigned int zend_mm_low_bit ( size_t _size )
{
# if defined(__GNUC__) && defined(i386)
2007-12-20 20:58:46 +08:00
unsigned int n ;
2007-03-20 14:46:48 +08:00
__asm__ ( " bsfl %1,%0 \n \t " : " =r " ( n ) : " rm " ( _size ) ) ;
return n ;
2007-12-20 20:58:46 +08:00
# elif defined(__GNUC__) && defined(__x86_64__)
unsigned long n ;
__asm__ ( " bsfq %1,%0 \n \t " : " =r " ( n ) : " rm " ( _size ) ) ;
return ( unsigned int ) n ;
2007-03-20 14:46:48 +08:00
# elif defined(_MSC_VER) && defined(_M_IX86)
__asm {
bsf eax , _size
}
# else
static const int offset [ 16 ] = { 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 } ;
unsigned int n ;
unsigned int index = 0 ;
do {
n = offset [ _size & 15 ] ;
_size > > = 4 ;
index + = n ;
} while ( n = = 4 ) ;
return index ;
# endif
}
static inline void zend_mm_add_to_rest_list ( zend_mm_heap * heap , zend_mm_free_block * mm_block )
2006-07-18 17:06:33 +08:00
{
zend_mm_free_block * prev , * next ;
2007-03-20 14:46:48 +08:00
ZEND_MM_SET_MAGIC ( mm_block , MEM_BLOCK_FREED ) ;
if ( ! ZEND_MM_SMALL_SIZE ( ZEND_MM_FREE_BLOCK_SIZE ( mm_block ) ) ) {
mm_block - > parent = NULL ;
}
prev = heap - > rest_buckets [ 0 ] ;
next = prev - > next_free_block ;
mm_block - > prev_free_block = prev ;
mm_block - > next_free_block = next ;
prev - > next_free_block = next - > prev_free_block = mm_block ;
}
static inline void zend_mm_add_to_free_list ( zend_mm_heap * heap , zend_mm_free_block * mm_block )
{
2006-07-18 17:06:33 +08:00
size_t size ;
2007-03-20 14:46:48 +08:00
size_t index ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
ZEND_MM_SET_MAGIC ( mm_block , MEM_BLOCK_FREED ) ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
size = ZEND_MM_FREE_BLOCK_SIZE ( mm_block ) ;
2007-03-20 14:46:48 +08:00
if ( EXPECTED ( ! ZEND_MM_SMALL_SIZE ( size ) ) ) {
zend_mm_free_block * * p ;
index = ZEND_MM_LARGE_BUCKET_INDEX ( size ) ;
p = & heap - > large_free_buckets [ index ] ;
mm_block - > child [ 0 ] = mm_block - > child [ 1 ] = NULL ;
if ( ! * p ) {
* p = mm_block ;
mm_block - > parent = p ;
mm_block - > prev_free_block = mm_block - > next_free_block = mm_block ;
2007-04-09 23:38:58 +08:00
heap - > large_free_bitmap | = ( ZEND_MM_LONG_CONST ( 1 ) < < index ) ;
2007-03-20 14:46:48 +08:00
} else {
size_t m ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
for ( m = size < < ( ZEND_MM_NUM_BUCKETS - index ) ; ; m < < = 1 ) {
zend_mm_free_block * prev = * p ;
if ( ZEND_MM_FREE_BLOCK_SIZE ( prev ) ! = size ) {
p = & prev - > child [ ( m > > ( ZEND_MM_NUM_BUCKETS - 1 ) ) & 1 ] ;
if ( ! * p ) {
* p = mm_block ;
mm_block - > parent = p ;
mm_block - > prev_free_block = mm_block - > next_free_block = mm_block ;
break ;
}
} else {
zend_mm_free_block * next = prev - > next_free_block ;
prev - > next_free_block = next - > prev_free_block = mm_block ;
mm_block - > next_free_block = next ;
mm_block - > prev_free_block = prev ;
mm_block - > parent = NULL ;
break ;
}
}
2006-07-18 17:06:33 +08:00
}
} else {
2007-03-20 14:46:48 +08:00
zend_mm_free_block * prev , * next ;
index = ZEND_MM_BUCKET_INDEX ( size ) ;
prev = ZEND_MM_SMALL_FREE_BUCKET ( heap , index ) ;
if ( prev - > prev_free_block = = prev ) {
2007-04-09 23:38:58 +08:00
heap - > free_bitmap | = ( ZEND_MM_LONG_CONST ( 1 ) < < index ) ;
2006-12-02 04:01:50 +08:00
}
2007-03-20 14:46:48 +08:00
next = prev - > next_free_block ;
mm_block - > prev_free_block = prev ;
mm_block - > next_free_block = next ;
prev - > next_free_block = next - > prev_free_block = mm_block ;
2006-07-18 17:06:33 +08:00
}
}
static inline void zend_mm_remove_from_free_list ( zend_mm_heap * heap , zend_mm_free_block * mm_block )
{
2007-03-20 14:46:48 +08:00
zend_mm_free_block * prev = mm_block - > prev_free_block ;
zend_mm_free_block * next = mm_block - > next_free_block ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
ZEND_MM_CHECK_MAGIC ( mm_block , MEM_BLOCK_FREED ) ;
2007-03-20 14:46:48 +08:00
if ( EXPECTED ( prev = = mm_block ) ) {
zend_mm_free_block * * rp , * * cp ;
2006-12-15 21:25:26 +08:00
# if ZEND_MM_SAFE_UNLINKING
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( next ! = mm_block ) ) {
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
2006-12-15 21:25:26 +08:00
# endif
2007-03-20 14:46:48 +08:00
rp = & mm_block - > child [ mm_block - > child [ 1 ] ! = NULL ] ;
prev = * rp ;
if ( EXPECTED ( prev = = NULL ) ) {
size_t index = ZEND_MM_LARGE_BUCKET_INDEX ( ZEND_MM_FREE_BLOCK_SIZE ( mm_block ) ) ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
ZEND_MM_CHECK_TREE ( mm_block ) ;
* mm_block - > parent = NULL ;
if ( mm_block - > parent = = & heap - > large_free_buckets [ index ] ) {
2007-04-09 23:38:58 +08:00
heap - > large_free_bitmap & = ~ ( ZEND_MM_LONG_CONST ( 1 ) < < index ) ;
2007-03-20 14:46:48 +08:00
}
} else {
while ( * ( cp = & ( prev - > child [ prev - > child [ 1 ] ! = NULL ] ) ) ! = NULL ) {
prev = * cp ;
rp = cp ;
}
* rp = NULL ;
subst_block :
ZEND_MM_CHECK_TREE ( mm_block ) ;
* mm_block - > parent = prev ;
prev - > parent = mm_block - > parent ;
if ( ( prev - > child [ 0 ] = mm_block - > child [ 0 ] ) ) {
ZEND_MM_CHECK_TREE ( prev - > child [ 0 ] ) ;
prev - > child [ 0 ] - > parent = & prev - > child [ 0 ] ;
}
if ( ( prev - > child [ 1 ] = mm_block - > child [ 1 ] ) ) {
ZEND_MM_CHECK_TREE ( prev - > child [ 1 ] ) ;
prev - > child [ 1 ] - > parent = & prev - > child [ 1 ] ;
}
}
} else {
# if ZEND_MM_SAFE_UNLINKING
if ( UNEXPECTED ( prev - > next_free_block ! = mm_block ) | | UNEXPECTED ( next - > prev_free_block ! = mm_block ) ) {
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
# endif
prev - > next_free_block = next ;
next - > prev_free_block = prev ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
if ( EXPECTED ( ZEND_MM_SMALL_SIZE ( ZEND_MM_FREE_BLOCK_SIZE ( mm_block ) ) ) ) {
if ( EXPECTED ( prev = = next ) ) {
size_t index = ZEND_MM_BUCKET_INDEX ( ZEND_MM_FREE_BLOCK_SIZE ( mm_block ) ) ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
if ( EXPECTED ( heap - > free_buckets [ index * 2 ] = = heap - > free_buckets [ index * 2 + 1 ] ) ) {
2007-04-09 23:38:58 +08:00
heap - > free_bitmap & = ~ ( ZEND_MM_LONG_CONST ( 1 ) < < index ) ;
2007-03-20 14:46:48 +08:00
}
}
} else if ( UNEXPECTED ( mm_block - > parent ! = NULL ) ) {
goto subst_block ;
2006-07-18 17:06:33 +08:00
}
}
}
static inline void zend_mm_init ( zend_mm_heap * heap )
{
2007-03-20 14:46:48 +08:00
zend_mm_free_block * p ;
2006-07-18 17:06:33 +08:00
int i ;
heap - > free_bitmap = 0 ;
2007-03-20 14:46:48 +08:00
heap - > large_free_bitmap = 0 ;
2006-07-18 17:06:33 +08:00
# if ZEND_MM_CACHE
heap - > cached = 0 ;
memset ( heap - > cache , 0 , sizeof ( heap - > cache ) ) ;
1999-04-08 02:10:10 +08:00
# endif
2007-03-20 14:46:48 +08:00
# if ZEND_MM_CACHE_STAT
2006-07-18 17:06:33 +08:00
for ( i = 0 ; i < ZEND_MM_NUM_BUCKETS ; i + + ) {
2007-03-20 14:46:48 +08:00
heap - > cache_stat [ i ] . count = 0 ;
2006-07-18 17:06:33 +08:00
}
2007-03-20 14:46:48 +08:00
# endif
p = ZEND_MM_SMALL_FREE_BUCKET ( heap , 0 ) ;
for ( i = 0 ; i < ZEND_MM_NUM_BUCKETS ; i + + ) {
p - > next_free_block = p ;
p - > prev_free_block = p ;
p = ( zend_mm_free_block * ) ( ( char * ) p + sizeof ( zend_mm_free_block * ) * 2 ) ;
heap - > large_free_buckets [ i ] = NULL ;
}
heap - > rest_buckets [ 0 ] = heap - > rest_buckets [ 1 ] = ZEND_MM_REST_BUCKET ( heap ) ;
2006-07-18 17:06:33 +08:00
}
static void zend_mm_del_segment ( zend_mm_heap * heap , zend_mm_segment * segment )
{
2007-03-20 14:46:48 +08:00
zend_mm_segment * * p = & heap - > segments_list ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
while ( * p ! = segment ) {
p = & ( * p ) - > next_segment ;
2006-07-18 17:06:33 +08:00
}
2007-03-20 14:46:48 +08:00
* p = segment - > next_segment ;
2006-07-25 21:40:05 +08:00
heap - > real_size - = segment - > size ;
2006-07-18 17:06:33 +08:00
ZEND_MM_STORAGE_FREE ( segment ) ;
}
# if ZEND_MM_CACHE
static void zend_mm_free_cache ( zend_mm_heap * heap )
{
int i ;
for ( i = 0 ; i < ZEND_MM_NUM_BUCKETS ; i + + ) {
if ( heap - > cache [ i ] ) {
zend_mm_free_block * mm_block = heap - > cache [ i ] ;
while ( mm_block ) {
size_t size = ZEND_MM_BLOCK_SIZE ( mm_block ) ;
zend_mm_free_block * q = mm_block - > prev_free_block ;
zend_mm_block * next_block = ZEND_MM_NEXT_BLOCK ( mm_block ) ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
heap - > cached - = size ;
1999-04-08 02:10:10 +08:00
2006-12-08 20:47:45 +08:00
if ( ZEND_MM_PREV_BLOCK_IS_FREE ( mm_block ) ) {
mm_block = ( zend_mm_free_block * ) ZEND_MM_PREV_BLOCK ( mm_block ) ;
size + = ZEND_MM_FREE_BLOCK_SIZE ( mm_block ) ;
zend_mm_remove_from_free_list ( heap , ( zend_mm_free_block * ) mm_block ) ;
2006-07-18 17:06:33 +08:00
}
if ( ZEND_MM_IS_FREE_BLOCK ( next_block ) ) {
size + = ZEND_MM_FREE_BLOCK_SIZE ( next_block ) ;
zend_mm_remove_from_free_list ( heap , ( zend_mm_free_block * ) next_block ) ;
}
ZEND_MM_BLOCK ( mm_block , ZEND_MM_FREE_BLOCK , size ) ;
if ( ZEND_MM_IS_FIRST_BLOCK ( mm_block ) & &
ZEND_MM_IS_GUARD_BLOCK ( ZEND_MM_NEXT_BLOCK ( mm_block ) ) ) {
zend_mm_del_segment ( heap , ( zend_mm_segment * ) ( ( char * ) mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE ) ) ;
} else {
zend_mm_add_to_free_list ( heap , ( zend_mm_free_block * ) mm_block ) ;
}
mm_block = q ;
}
heap - > cache [ i ] = NULL ;
2007-03-20 14:46:48 +08:00
# if ZEND_MM_CACHE_STAT
heap - > cache_stat [ i ] . count = 0 ;
# endif
2006-07-18 17:06:33 +08:00
}
1999-04-08 02:10:10 +08:00
}
2006-07-18 17:06:33 +08:00
}
2004-05-25 18:09:46 +08:00
# endif
1999-04-08 02:10:10 +08:00
2007-03-07 04:59:13 +08:00
# if ZEND_MM_HEAP_PROTECTION || ZEND_MM_COOKIES
2006-12-18 19:39:19 +08:00
static void zend_mm_random ( unsigned char * buf , size_t size )
{
size_t i = 0 ;
unsigned char t ;
# ifdef ZEND_WIN32
HCRYPTPROV hCryptProv ;
if ( CryptAcquireContext ( & hCryptProv , NULL , NULL , PROV_RSA_FULL , 0 ) ) {
do {
BOOL ret = CryptGenRandom ( hCryptProv , size , buf ) ;
CryptReleaseContext ( hCryptProv , 0 ) ;
if ( ret ) {
while ( i < size & & buf [ i ] ! = 0 ) {
i + + ;
}
if ( i = = size ) {
return ;
}
}
} while ( 0 ) ;
}
# elif defined(HAVE_DEV_URANDOM)
int fd = open ( " /dev/urandom " , 0 ) ;
if ( fd > = 0 ) {
if ( read ( fd , buf , size ) = = size ) {
while ( i < size & & buf [ i ] ! = 0 ) {
i + + ;
}
if ( i = = size ) {
close ( fd ) ;
return ;
}
}
close ( fd ) ;
}
# endif
t = ( unsigned char ) getpid ( ) ;
while ( i < size ) {
do {
buf [ i ] = ( ( unsigned char ) rand ( ) ) ^ t ;
} while ( buf [ i ] = = 0 ) ;
t = buf [ i + + ] < < 1 ;
}
}
2007-03-07 04:59:13 +08:00
# endif
2006-12-18 19:39:19 +08:00
2006-07-18 17:06:33 +08:00
/* Notes:
* - This function may alter the block_sizes values to match platform alignment
* - This function does * not * perform sanity checks on the arguments
*/
2007-03-20 14:46:48 +08:00
ZEND_API zend_mm_heap * zend_mm_startup_ex ( const zend_mm_mem_handlers * handlers , size_t block_size , size_t reserve_size , int internal , void * params )
2006-07-18 17:06:33 +08:00
{
zend_mm_storage * storage ;
zend_mm_heap * heap ;
#if 0
2006-11-23 17:32:39 +08:00
int i ;
2006-12-01 23:33:06 +08:00
printf ( " ZEND_MM_ALIGNMENT=%d \n " , ZEND_MM_ALIGNMENT ) ;
printf ( " ZEND_MM_ALIGNMENT_LOG2=%d \n " , ZEND_MM_ALIGNMENT_LOG2 ) ;
2006-11-23 17:32:39 +08:00
printf ( " ZEND_MM_MIN_SIZE=%d \n " , ZEND_MM_MIN_SIZE ) ;
printf ( " ZEND_MM_MAX_SMALL_SIZE=%d \n " , ZEND_MM_MAX_SMALL_SIZE ) ;
printf ( " ZEND_MM_ALIGNED_HEADER_SIZE=%d \n " , ZEND_MM_ALIGNED_HEADER_SIZE ) ;
printf ( " ZEND_MM_ALIGNED_FREE_HEADER_SIZE=%d \n " , ZEND_MM_ALIGNED_FREE_HEADER_SIZE ) ;
printf ( " ZEND_MM_MIN_ALLOC_BLOCK_SIZE=%d \n " , ZEND_MM_MIN_ALLOC_BLOCK_SIZE ) ;
printf ( " ZEND_MM_ALIGNED_MIN_HEADER_SIZE=%d \n " , ZEND_MM_ALIGNED_MIN_HEADER_SIZE ) ;
printf ( " ZEND_MM_ALIGNED_SEGMENT_SIZE=%d \n " , ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
2006-07-18 17:06:33 +08:00
for ( i = 0 ; i < ZEND_MM_MAX_SMALL_SIZE ; i + + ) {
printf ( " %3d%c: %3ld %d %2ld \n " , i , ( i = = ZEND_MM_MIN_SIZE ? ' * ' : ' ' ) , ( long ) ZEND_MM_TRUE_SIZE ( i ) , ZEND_MM_SMALL_SIZE ( ZEND_MM_TRUE_SIZE ( i ) ) , ( long ) ZEND_MM_BUCKET_INDEX ( ZEND_MM_TRUE_SIZE ( i ) ) ) ;
}
exit ( 0 ) ;
2004-05-25 18:09:46 +08:00
# endif
1999-04-08 02:10:10 +08:00
2006-12-15 21:25:26 +08:00
# if ZEND_MM_HEAP_PROTECTION
if ( _mem_block_start_magic = = 0 ) {
2006-12-18 19:39:19 +08:00
zend_mm_random ( ( unsigned char * ) & _mem_block_start_magic , sizeof ( _mem_block_start_magic ) ) ;
2006-12-15 21:25:26 +08:00
}
if ( _mem_block_end_magic = = 0 ) {
2006-12-18 19:39:19 +08:00
zend_mm_random ( ( unsigned char * ) & _mem_block_end_magic , sizeof ( _mem_block_end_magic ) ) ;
2006-12-15 21:25:26 +08:00
}
# endif
# if ZEND_MM_COOKIES
if ( _zend_mm_cookie = = 0 ) {
2006-12-18 19:39:19 +08:00
zend_mm_random ( ( unsigned char * ) & _zend_mm_cookie , sizeof ( _zend_mm_cookie ) ) ;
2006-12-15 21:25:26 +08:00
}
# endif
2007-03-20 14:46:48 +08:00
if ( zend_mm_low_bit ( block_size ) ! = zend_mm_high_bit ( block_size ) ) {
fprintf ( stderr , " 'block_size' must be a power of two \n " ) ;
exit ( 255 ) ;
}
2006-07-18 17:06:33 +08:00
storage = handlers - > init ( params ) ;
if ( ! storage ) {
2006-08-31 19:53:57 +08:00
fprintf ( stderr , " Cannot initialize zend_mm storage [%s] \n " , handlers - > name ) ;
2006-07-18 17:06:33 +08:00
exit ( 255 ) ;
}
storage - > handlers = handlers ;
heap = malloc ( sizeof ( struct _zend_mm_heap ) ) ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
heap - > storage = storage ;
2007-03-20 14:46:48 +08:00
heap - > block_size = block_size ;
2007-10-25 15:32:40 +08:00
heap - > compact_size = 0 ;
2006-07-18 17:06:33 +08:00
heap - > segments_list = NULL ;
zend_mm_init ( heap ) ;
2007-03-20 14:46:48 +08:00
# if ZEND_MM_CACHE_STAT
memset ( heap - > cache_stat , 0 , sizeof ( heap - > cache_stat ) ) ;
# endif
2000-06-09 23:54:14 +08:00
2006-07-18 17:06:33 +08:00
heap - > use_zend_alloc = 1 ;
2006-07-25 21:40:05 +08:00
heap - > real_size = 0 ;
2006-12-05 00:20:02 +08:00
heap - > overflow = 0 ;
2006-07-25 21:40:05 +08:00
heap - > real_peak = 0 ;
2007-04-09 23:38:58 +08:00
heap - > limit = ZEND_MM_LONG_CONST ( 1 ) < < ( ZEND_MM_NUM_BUCKETS - 2 ) ;
2006-07-25 21:40:05 +08:00
heap - > size = 0 ;
heap - > peak = 0 ;
2007-03-20 14:46:48 +08:00
heap - > internal = internal ;
2006-12-05 00:20:02 +08:00
heap - > reserve = NULL ;
2007-03-20 14:46:48 +08:00
heap - > reserve_size = reserve_size ;
if ( reserve_size > 0 ) {
heap - > reserve = _zend_mm_alloc_int ( heap , reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC ) ;
}
if ( internal ) {
int i ;
2008-10-30 16:55:20 +08:00
zend_mm_free_block * p , * q , * orig ;
2007-03-20 14:46:48 +08:00
zend_mm_heap * mm_heap = _zend_mm_alloc_int ( heap , sizeof ( zend_mm_heap ) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC ) ;
* mm_heap = * heap ;
p = ZEND_MM_SMALL_FREE_BUCKET ( mm_heap , 0 ) ;
2008-10-30 16:55:20 +08:00
orig = ZEND_MM_SMALL_FREE_BUCKET ( heap , 0 ) ;
2007-03-20 14:46:48 +08:00
for ( i = 0 ; i < ZEND_MM_NUM_BUCKETS ; i + + ) {
2008-10-30 16:55:20 +08:00
q = p ;
while ( q - > prev_free_block ! = orig ) {
q = q - > prev_free_block ;
}
q - > prev_free_block = p ;
q = p ;
while ( q - > next_free_block ! = orig ) {
q = q - > next_free_block ;
}
q - > next_free_block = p ;
2007-03-20 14:46:48 +08:00
p = ( zend_mm_free_block * ) ( ( char * ) p + sizeof ( zend_mm_free_block * ) * 2 ) ;
2008-10-30 16:55:20 +08:00
orig = ( zend_mm_free_block * ) ( ( char * ) orig + sizeof ( zend_mm_free_block * ) * 2 ) ;
2007-03-20 14:46:48 +08:00
if ( mm_heap - > large_free_buckets [ i ] ) {
mm_heap - > large_free_buckets [ i ] - > parent = & mm_heap - > large_free_buckets [ i ] ;
}
}
mm_heap - > rest_buckets [ 0 ] - > next_free_block = mm_heap - > rest_buckets [ 1 ] - > prev_free_block = ZEND_MM_REST_BUCKET ( mm_heap ) ;
2000-06-09 23:54:14 +08:00
2007-03-20 14:46:48 +08:00
free ( heap ) ;
heap = mm_heap ;
}
2006-07-18 17:06:33 +08:00
return heap ;
}
ZEND_API zend_mm_heap * zend_mm_startup ( void )
{
int i ;
size_t seg_size ;
char * mem_type = getenv ( " ZEND_MM_MEM_TYPE " ) ;
char * tmp ;
const zend_mm_mem_handlers * handlers ;
2007-10-25 15:32:40 +08:00
zend_mm_heap * heap ;
2006-07-18 17:06:33 +08:00
if ( mem_type = = NULL ) {
i = 0 ;
} else {
for ( i = 0 ; mem_handlers [ i ] . name ; i + + ) {
if ( strcmp ( mem_handlers [ i ] . name , mem_type ) = = 0 ) {
break ;
}
}
if ( ! mem_handlers [ i ] . name ) {
fprintf ( stderr , " Wrong or unsupported zend_mm storage type '%s' \n " , mem_type ) ;
fprintf ( stderr , " supported types: \n " ) ;
for ( i = 0 ; mem_handlers [ i ] . name ; i + + ) {
fprintf ( stderr , " '%s' \n " , mem_handlers [ i ] . name ) ;
}
exit ( 255 ) ;
}
}
handlers = & mem_handlers [ i ] ;
tmp = getenv ( " ZEND_MM_SEG_SIZE " ) ;
if ( tmp ) {
seg_size = zend_atoi ( tmp , 0 ) ;
2007-03-20 14:46:48 +08:00
if ( zend_mm_low_bit ( seg_size ) ! = zend_mm_high_bit ( seg_size ) ) {
2008-05-11 19:46:44 +08:00
fprintf ( stderr , " ZEND_MM_SEG_SIZE must be a power of two \n " ) ;
2007-03-20 14:46:48 +08:00
exit ( 255 ) ;
2008-07-22 01:06:35 +08:00
} else if ( seg_size < ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE ) {
fprintf ( stderr , " ZEND_MM_SEG_SIZE is too small \n " ) ;
exit ( 255 ) ;
2007-03-20 14:46:48 +08:00
}
2006-07-18 17:06:33 +08:00
} else {
2007-03-20 14:46:48 +08:00
seg_size = ZEND_MM_SEG_SIZE ;
2006-07-18 17:06:33 +08:00
}
2007-10-25 15:32:40 +08:00
heap = zend_mm_startup_ex ( handlers , seg_size , ZEND_MM_RESERVE_SIZE , 0 , NULL ) ;
if ( heap ) {
tmp = getenv ( " ZEND_MM_COMPACT " ) ;
if ( tmp ) {
heap - > compact_size = zend_atoi ( tmp , 0 ) ;
} else {
heap - > compact_size = 2 * 1024 * 1024 ;
}
}
return heap ;
2006-07-18 17:06:33 +08:00
}
# if ZEND_DEBUG
static long zend_mm_find_leaks ( zend_mm_segment * segment , zend_mm_block * b )
{
long leaks = 0 ;
zend_mm_block * p , * q ;
p = ZEND_MM_NEXT_BLOCK ( b ) ;
while ( 1 ) {
2006-11-13 18:28:46 +08:00
if ( ZEND_MM_IS_GUARD_BLOCK ( p ) ) {
ZEND_MM_CHECK_MAGIC ( p , MEM_BLOCK_GUARD ) ;
segment = segment - > next_segment ;
if ( ! segment ) {
break ;
}
p = ( zend_mm_block * ) ( ( char * ) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
continue ;
}
2006-07-18 17:06:33 +08:00
q = ZEND_MM_NEXT_BLOCK ( p ) ;
if ( q < = p | |
( char * ) q > ( char * ) segment + segment - > size | |
p - > info . _size ! = q - > info . _prev ) {
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
if ( ! ZEND_MM_IS_FREE_BLOCK ( p ) ) {
if ( p - > magic = = MEM_BLOCK_VALID ) {
if ( p - > debug . filename = = b - > debug . filename & & p - > debug . lineno = = b - > debug . lineno ) {
ZEND_MM_SET_MAGIC ( p , MEM_BLOCK_LEAK ) ;
leaks + + ;
}
# if ZEND_MM_CACHE
} else if ( p - > magic = = MEM_BLOCK_CACHED ) {
/* skip it */
# endif
2006-07-24 16:15:26 +08:00
} else if ( p - > magic ! = MEM_BLOCK_LEAK ) {
2006-07-18 17:06:33 +08:00
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
}
p = q ;
}
return leaks ;
}
2008-08-16 03:47:33 +08:00
static void zend_mm_check_leaks ( zend_mm_heap * heap TSRMLS_DC )
2006-07-18 17:06:33 +08:00
{
zend_mm_segment * segment = heap - > segments_list ;
zend_mm_block * p , * q ;
zend_uint total = 0 ;
if ( ! segment ) {
return ;
}
p = ( zend_mm_block * ) ( ( char * ) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
while ( 1 ) {
q = ZEND_MM_NEXT_BLOCK ( p ) ;
if ( q < = p | |
( char * ) q > ( char * ) segment + segment - > size | |
p - > info . _size ! = q - > info . _prev ) {
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
if ( ! ZEND_MM_IS_FREE_BLOCK ( p ) ) {
if ( p - > magic = = MEM_BLOCK_VALID ) {
long repeated ;
zend_leak_info leak ;
ZEND_MM_SET_MAGIC ( p , MEM_BLOCK_LEAK ) ;
leak . addr = ZEND_MM_DATA_OF ( p ) ;
leak . size = p - > debug . size ;
leak . filename = p - > debug . filename ;
leak . lineno = p - > debug . lineno ;
leak . orig_filename = p - > debug . orig_filename ;
leak . orig_lineno = p - > debug . orig_lineno ;
2008-08-16 03:47:33 +08:00
zend_message_dispatcher ( ZMSG_LOG_SCRIPT_NAME , NULL TSRMLS_CC ) ;
zend_message_dispatcher ( ZMSG_MEMORY_LEAK_DETECTED , & leak TSRMLS_CC ) ;
2006-07-18 17:06:33 +08:00
repeated = zend_mm_find_leaks ( segment , p ) ;
total + = 1 + repeated ;
if ( repeated ) {
2008-08-16 03:47:33 +08:00
zend_message_dispatcher ( ZMSG_MEMORY_LEAK_REPEATED , ( void * ) ( zend_uintptr_t ) repeated TSRMLS_CC ) ;
2006-07-18 17:06:33 +08:00
}
# if ZEND_MM_CACHE
} else if ( p - > magic = = MEM_BLOCK_CACHED ) {
/* skip it */
# endif
} else if ( p - > magic ! = MEM_BLOCK_LEAK ) {
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
}
if ( ZEND_MM_IS_GUARD_BLOCK ( q ) ) {
segment = segment - > next_segment ;
if ( ! segment ) {
break ;
}
q = ( zend_mm_block * ) ( ( char * ) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
}
p = q ;
}
if ( total ) {
2008-08-16 03:47:33 +08:00
zend_message_dispatcher ( ZMSG_MEMORY_LEAKS_GRAND_TOTAL , & total TSRMLS_CC ) ;
2006-07-18 17:06:33 +08:00
}
}
static int zend_mm_check_ptr ( zend_mm_heap * heap , void * ptr , int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
zend_mm_block * p ;
int no_cache_notice = 0 ;
int had_problems = 0 ;
int valid_beginning = 1 ;
if ( silent = = 2 ) {
silent = 1 ;
no_cache_notice = 1 ;
} else if ( silent = = 3 ) {
silent = 0 ;
no_cache_notice = 1 ;
}
if ( ! silent ) {
2008-08-16 03:47:33 +08:00
TSRMLS_FETCH ( ) ;
zend_message_dispatcher ( ZMSG_LOG_SCRIPT_NAME , NULL TSRMLS_CC ) ;
2006-07-18 17:06:33 +08:00
zend_debug_alloc_output ( " --------------------------------------- \n " ) ;
2007-04-16 16:09:56 +08:00
zend_debug_alloc_output ( " %s(%d) : Block " PTR_FMT " status: \n " ZEND_FILE_LINE_RELAY_CC , ptr ) ;
2006-07-18 17:06:33 +08:00
if ( __zend_orig_filename ) {
zend_debug_alloc_output ( " %s(%d) : Actual location (location was relayed) \n " ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
if ( ! ptr ) {
zend_debug_alloc_output ( " NULL \n " ) ;
zend_debug_alloc_output ( " --------------------------------------- \n " ) ;
return 0 ;
}
}
if ( ! ptr ) {
if ( silent ) {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
}
p = ZEND_MM_HEADER_OF ( ptr ) ;
# ifdef ZTS
if ( ZEND_MM_BAD_THREAD_ID ( p ) ) {
if ( ! silent ) {
2006-08-31 06:29:24 +08:00
zend_debug_alloc_output ( " Invalid pointer: ((thread_id=0x%0.8X) != (expected=0x%0.8X)) \n " , ( long ) p - > thread_id , ( long ) tsrm_thread_id ( ) ) ;
2006-07-18 17:06:33 +08:00
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
}
# endif
if ( p - > info . _size ! = ZEND_MM_NEXT_BLOCK ( p ) - > info . _prev ) {
if ( ! silent ) {
2007-04-16 16:09:56 +08:00
zend_debug_alloc_output ( " Invalid pointer: ((size= " PTR_FMT " ) != (next.prev= " PTR_FMT " )) \n " , p - > info . _size , ZEND_MM_NEXT_BLOCK ( p ) - > info . _prev ) ;
2006-07-18 17:06:33 +08:00
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
}
if ( p - > info . _prev ! = ZEND_MM_GUARD_BLOCK & &
ZEND_MM_PREV_BLOCK ( p ) - > info . _size ! = p - > info . _prev ) {
if ( ! silent ) {
2007-04-16 16:09:56 +08:00
zend_debug_alloc_output ( " Invalid pointer: ((prev= " PTR_FMT " ) != (prev.size= " PTR_FMT " )) \n " , p - > info . _prev , ZEND_MM_PREV_BLOCK ( p ) - > info . _size ) ;
2006-07-18 17:06:33 +08:00
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
}
if ( had_problems ) {
zend_debug_alloc_output ( " --------------------------------------- \n " ) ;
return 0 ;
}
if ( ! silent ) {
zend_debug_alloc_output ( " %10s \t " , " Beginning: " ) ;
}
if ( ! ZEND_MM_IS_USED_BLOCK ( p ) ) {
if ( ! silent ) {
if ( p - > magic ! = MEM_BLOCK_FREED ) {
zend_debug_alloc_output ( " Freed (magic=0x%0.8X, expected=0x%0.8X) \n " , p - > magic , MEM_BLOCK_FREED ) ;
} else {
zend_debug_alloc_output ( " Freed \n " ) ;
}
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
} else if ( ZEND_MM_IS_GUARD_BLOCK ( p ) ) {
if ( ! silent ) {
if ( p - > magic ! = MEM_BLOCK_FREED ) {
zend_debug_alloc_output ( " Guard (magic=0x%0.8X, expected=0x%0.8X) \n " , p - > magic , MEM_BLOCK_FREED ) ;
} else {
zend_debug_alloc_output ( " Guard \n " ) ;
}
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
} else {
switch ( p - > magic ) {
case MEM_BLOCK_VALID :
case MEM_BLOCK_LEAK :
if ( ! silent ) {
zend_debug_alloc_output ( " OK (allocated on %s:%d, %d bytes) \n " , p - > debug . filename , p - > debug . lineno , ( int ) p - > debug . size ) ;
}
break ; /* ok */
case MEM_BLOCK_CACHED :
if ( ! no_cache_notice ) {
if ( ! silent ) {
zend_debug_alloc_output ( " Cached \n " ) ;
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
}
case MEM_BLOCK_FREED :
if ( ! silent ) {
zend_debug_alloc_output ( " Freed (invalid) \n " ) ;
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
break ;
case MEM_BLOCK_GUARD :
if ( ! silent ) {
zend_debug_alloc_output ( " Guard (invalid) \n " ) ;
had_problems = 1 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
break ;
default :
if ( ! silent ) {
zend_debug_alloc_output ( " Unknown (magic=0x%0.8X, expected=0x%0.8X) \n " , p - > magic , MEM_BLOCK_VALID ) ;
had_problems = 1 ;
valid_beginning = 0 ;
} else {
return zend_mm_check_ptr ( heap , ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
break ;
}
}
2006-12-15 21:25:26 +08:00
# if ZEND_MM_HEAP_PROTECTION
2006-07-18 17:06:33 +08:00
if ( ! valid_beginning ) {
if ( ! silent ) {
2006-12-15 21:25:26 +08:00
zend_debug_alloc_output ( " %10s \t " , " Start: " ) ;
2006-07-18 17:06:33 +08:00
zend_debug_alloc_output ( " Unknown \n " ) ;
zend_debug_alloc_output ( " %10s \t " , " End: " ) ;
2006-12-15 21:25:26 +08:00
zend_debug_alloc_output ( " Unknown \n " ) ;
2006-07-18 17:06:33 +08:00
}
} else {
2007-02-20 02:29:31 +08:00
char * end_magic = ZEND_MM_END_MAGIC_PTR ( p ) ;
2006-07-18 17:06:33 +08:00
2006-12-15 21:25:26 +08:00
if ( p - > debug . start_magic = = _mem_block_start_magic ) {
if ( ! silent ) {
zend_debug_alloc_output ( " %10s \t " , " Start: " ) ;
zend_debug_alloc_output ( " OK \n " ) ;
}
} else {
char * overflow_ptr , * magic_ptr = ( char * ) & _mem_block_start_magic ;
int overflows = 0 ;
int i ;
2006-07-18 17:06:33 +08:00
2006-12-15 21:25:26 +08:00
if ( silent ) {
return _mem_block_check ( ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
had_problems = 1 ;
overflow_ptr = ( char * ) & p - > debug . start_magic ;
i = END_MAGIC_SIZE ;
while ( - - i > = 0 ) {
if ( overflow_ptr [ i ] ! = magic_ptr [ i ] ) {
overflows + + ;
}
}
zend_debug_alloc_output ( " %10s \t " , " Start: " ) ;
zend_debug_alloc_output ( " Overflown (magic=0x%0.8X instead of 0x%0.8X) \n " , p - > debug . start_magic , _mem_block_start_magic ) ;
zend_debug_alloc_output ( " %10s \t " , " " ) ;
if ( overflows > = END_MAGIC_SIZE ) {
zend_debug_alloc_output ( " At least %d bytes overflown \n " , END_MAGIC_SIZE ) ;
} else {
zend_debug_alloc_output ( " %d byte(s) overflown \n " , overflows ) ;
2006-07-18 17:06:33 +08:00
}
}
2006-12-15 21:25:26 +08:00
if ( memcmp ( end_magic , & _mem_block_end_magic , END_MAGIC_SIZE ) = = 0 ) {
if ( ! silent ) {
zend_debug_alloc_output ( " %10s \t " , " End: " ) ;
zend_debug_alloc_output ( " OK \n " ) ;
}
2006-07-18 17:06:33 +08:00
} else {
2006-12-15 21:25:26 +08:00
char * overflow_ptr , * magic_ptr = ( char * ) & _mem_block_end_magic ;
int overflows = 0 ;
int i ;
if ( silent ) {
return _mem_block_check ( ptr , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
had_problems = 1 ;
overflow_ptr = ( char * ) end_magic ;
for ( i = 0 ; i < END_MAGIC_SIZE ; i + + ) {
if ( overflow_ptr [ i ] ! = magic_ptr [ i ] ) {
overflows + + ;
}
}
zend_debug_alloc_output ( " %10s \t " , " End: " ) ;
zend_debug_alloc_output ( " Overflown (magic=0x%0.8X instead of 0x%0.8X) \n " , * end_magic , _mem_block_end_magic ) ;
zend_debug_alloc_output ( " %10s \t " , " " ) ;
if ( overflows > = END_MAGIC_SIZE ) {
zend_debug_alloc_output ( " At least %d bytes overflown \n " , END_MAGIC_SIZE ) ;
} else {
zend_debug_alloc_output ( " %d byte(s) overflown \n " , overflows ) ;
}
2006-07-18 17:06:33 +08:00
}
}
2006-12-15 21:25:26 +08:00
# endif
2006-07-18 17:06:33 +08:00
if ( ! silent ) {
zend_debug_alloc_output ( " --------------------------------------- \n " ) ;
}
return ( ( ! had_problems ) ? 1 : 0 ) ;
}
static int zend_mm_check_heap ( zend_mm_heap * heap , int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
zend_mm_segment * segment = heap - > segments_list ;
zend_mm_block * p , * q ;
int errors = 0 ;
if ( ! segment ) {
return 0 ;
}
p = ( zend_mm_block * ) ( ( char * ) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
while ( 1 ) {
q = ZEND_MM_NEXT_BLOCK ( p ) ;
if ( q < = p | |
( char * ) q > ( char * ) segment + segment - > size | |
p - > info . _size ! = q - > info . _prev ) {
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
if ( ! ZEND_MM_IS_FREE_BLOCK ( p ) ) {
if ( p - > magic = = MEM_BLOCK_VALID | | p - > magic = = MEM_BLOCK_LEAK ) {
if ( ! zend_mm_check_ptr ( heap , ZEND_MM_DATA_OF ( p ) , ( silent ? 2 : 3 ) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ) {
errors + + ;
}
# if ZEND_MM_CACHE
} else if ( p - > magic = = MEM_BLOCK_CACHED ) {
/* skip it */
# endif
} else if ( p - > magic ! = MEM_BLOCK_LEAK ) {
zend_mm_panic ( " zend_mm_heap corrupted " ) ;
}
}
if ( ZEND_MM_IS_GUARD_BLOCK ( q ) ) {
segment = segment - > next_segment ;
if ( ! segment ) {
return errors ;
}
q = ( zend_mm_block * ) ( ( char * ) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
}
p = q ;
}
}
# endif
2008-08-16 03:47:33 +08:00
ZEND_API void zend_mm_shutdown ( zend_mm_heap * heap , int full_shutdown , int silent TSRMLS_DC )
2006-07-18 17:06:33 +08:00
{
2007-03-20 14:46:48 +08:00
zend_mm_storage * storage ;
2006-07-18 17:06:33 +08:00
zend_mm_segment * segment ;
zend_mm_segment * prev ;
2007-03-20 14:46:48 +08:00
int internal ;
2006-07-18 17:06:33 +08:00
2006-12-05 00:20:02 +08:00
if ( heap - > reserve ) {
2007-03-20 14:46:48 +08:00
# if ZEND_DEBUG
if ( ! silent ) {
_zend_mm_free_int ( heap , heap - > reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC ) ;
}
# endif
2006-12-05 00:20:02 +08:00
heap - > reserve = NULL ;
}
2007-03-20 14:46:48 +08:00
# if ZEND_MM_CACHE_STAT
if ( full_shutdown ) {
FILE * f ;
f = fopen ( " zend_mm.log " , " w " ) ;
if ( f ) {
int i , j ;
size_t size , true_size , min_size , max_size ;
int hit = 0 , miss = 0 ;
fprintf ( f , " \n idx min_size max_size true_size max_len hits misses \n " ) ;
size = 0 ;
while ( 1 ) {
true_size = ZEND_MM_TRUE_SIZE ( size ) ;
if ( ZEND_MM_SMALL_SIZE ( true_size ) ) {
min_size = size ;
i = ZEND_MM_BUCKET_INDEX ( true_size ) ;
size + + ;
while ( 1 ) {
true_size = ZEND_MM_TRUE_SIZE ( size ) ;
if ( ZEND_MM_SMALL_SIZE ( true_size ) ) {
j = ZEND_MM_BUCKET_INDEX ( true_size ) ;
if ( j > i ) {
max_size = size - 1 ;
break ;
}
} else {
max_size = size - 1 ;
break ;
}
size + + ;
}
hit + = heap - > cache_stat [ i ] . hit ;
miss + = heap - > cache_stat [ i ] . miss ;
fprintf ( f , " %2d %8d %8d %9d %8d %8d %8d \n " , i , ( int ) min_size , ( int ) max_size , ZEND_MM_TRUE_SIZE ( max_size ) , heap - > cache_stat [ i ] . max_count , heap - > cache_stat [ i ] . hit , heap - > cache_stat [ i ] . miss ) ;
} else {
break ;
}
}
fprintf ( f , " %8d %8d \n " , hit , miss ) ;
fprintf ( f , " %8d %8d \n " , heap - > cache_stat [ ZEND_MM_NUM_BUCKETS ] . hit , heap - > cache_stat [ ZEND_MM_NUM_BUCKETS ] . miss ) ;
fclose ( f ) ;
}
}
# endif
2006-07-18 17:06:33 +08:00
# if ZEND_DEBUG
if ( ! silent ) {
2008-08-16 03:47:33 +08:00
zend_mm_check_leaks ( heap TSRMLS_CC ) ;
2006-07-18 17:06:33 +08:00
}
# endif
2007-03-20 14:46:48 +08:00
internal = heap - > internal ;
storage = heap - > storage ;
2006-07-18 17:06:33 +08:00
segment = heap - > segments_list ;
while ( segment ) {
prev = segment ;
segment = segment - > next_segment ;
ZEND_MM_STORAGE_FREE ( prev ) ;
}
if ( full_shutdown ) {
2007-03-20 14:46:48 +08:00
storage - > handlers - > dtor ( storage ) ;
if ( ! internal ) {
free ( heap ) ;
}
2006-07-18 17:06:33 +08:00
} else {
2007-10-25 15:32:40 +08:00
if ( heap - > compact_size & &
heap - > real_peak > heap - > compact_size ) {
storage - > handlers - > compact ( storage ) ;
}
2006-07-18 17:06:33 +08:00
heap - > segments_list = NULL ;
zend_mm_init ( heap ) ;
2006-07-25 21:40:05 +08:00
heap - > real_size = 0 ;
heap - > real_peak = 0 ;
heap - > size = 0 ;
2006-07-18 17:06:33 +08:00
heap - > peak = 0 ;
2007-03-20 14:46:48 +08:00
if ( heap - > reserve_size ) {
heap - > reserve = _zend_mm_alloc_int ( heap , heap - > reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC ) ;
}
2006-07-18 17:06:33 +08:00
heap - > overflow = 0 ;
}
}
static void zend_mm_safe_error ( zend_mm_heap * heap ,
const char * format ,
size_t limit ,
# if ZEND_DEBUG
const char * filename ,
uint lineno ,
# endif
size_t size )
{
2006-12-05 00:20:02 +08:00
if ( heap - > reserve ) {
2007-03-20 14:46:48 +08:00
_zend_mm_free_int ( heap , heap - > reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC ) ;
2006-12-05 00:20:02 +08:00
heap - > reserve = NULL ;
}
2006-07-18 17:06:33 +08:00
if ( heap - > overflow = = 0 ) {
char * error_filename ;
uint error_lineno ;
TSRMLS_FETCH ( ) ;
if ( zend_is_compiling ( TSRMLS_C ) ) {
error_filename = zend_get_compiled_filename ( TSRMLS_C ) ;
error_lineno = zend_get_compiled_lineno ( TSRMLS_C ) ;
} else if ( EG ( in_execution ) ) {
error_filename = EG ( active_op_array ) ? EG ( active_op_array ) - > filename : NULL ;
error_lineno = EG ( opline_ptr ) ? ( * EG ( opline_ptr ) ) - > lineno : 0 ;
} else {
error_filename = NULL ;
error_lineno = 0 ;
}
if ( ! error_filename ) {
error_filename = " Unknown " ;
}
heap - > overflow = 1 ;
zend_try {
2007-03-20 14:46:48 +08:00
zend_error_noreturn ( E_ERROR ,
2006-07-18 17:06:33 +08:00
format ,
limit ,
# if ZEND_DEBUG
filename ,
lineno ,
# endif
size ) ;
} zend_catch {
if ( heap - > overflow = = 2 ) {
fprintf ( stderr , " \n Fatal error: " ) ;
fprintf ( stderr ,
format ,
limit ,
# if ZEND_DEBUG
filename ,
lineno ,
# endif
size ) ;
fprintf ( stderr , " in %s on line %d \n " , error_filename , error_lineno ) ;
}
} zend_end_try ( ) ;
} else {
heap - > overflow = 2 ;
}
zend_bailout ( ) ;
}
2007-03-20 14:46:48 +08:00
static zend_mm_free_block * zend_mm_search_large_block ( zend_mm_heap * heap , size_t true_size )
{
zend_mm_free_block * best_fit ;
size_t index = ZEND_MM_LARGE_BUCKET_INDEX ( true_size ) ;
size_t bitmap = heap - > large_free_bitmap > > index ;
zend_mm_free_block * p ;
if ( bitmap = = 0 ) {
return NULL ;
}
if ( UNEXPECTED ( ( bitmap & 1 ) ! = 0 ) ) {
/* Search for best "large" free block */
zend_mm_free_block * rst = NULL ;
size_t m ;
size_t best_size = - 1 ;
best_fit = NULL ;
p = heap - > large_free_buckets [ index ] ;
for ( m = true_size < < ( ZEND_MM_NUM_BUCKETS - index ) ; ; m < < = 1 ) {
if ( UNEXPECTED ( ZEND_MM_FREE_BLOCK_SIZE ( p ) = = true_size ) ) {
return p - > next_free_block ;
} else if ( ZEND_MM_FREE_BLOCK_SIZE ( p ) > = true_size & &
ZEND_MM_FREE_BLOCK_SIZE ( p ) < best_size ) {
best_size = ZEND_MM_FREE_BLOCK_SIZE ( p ) ;
best_fit = p ;
}
2007-04-09 23:38:58 +08:00
if ( ( m & ( ZEND_MM_LONG_CONST ( 1 ) < < ( ZEND_MM_NUM_BUCKETS - 1 ) ) ) = = 0 ) {
2007-03-20 14:46:48 +08:00
if ( p - > child [ 1 ] ) {
rst = p - > child [ 1 ] ;
}
if ( p - > child [ 0 ] ) {
p = p - > child [ 0 ] ;
} else {
break ;
}
} else if ( p - > child [ 1 ] ) {
p = p - > child [ 1 ] ;
} else {
break ;
}
}
for ( p = rst ; p ; p = p - > child [ p - > child [ 0 ] ! = NULL ] ) {
if ( UNEXPECTED ( ZEND_MM_FREE_BLOCK_SIZE ( p ) = = true_size ) ) {
return p - > next_free_block ;
} else if ( ZEND_MM_FREE_BLOCK_SIZE ( p ) > true_size & &
ZEND_MM_FREE_BLOCK_SIZE ( p ) < best_size ) {
best_size = ZEND_MM_FREE_BLOCK_SIZE ( p ) ;
best_fit = p ;
}
}
if ( best_fit ) {
return best_fit - > next_free_block ;
}
bitmap = bitmap > > 1 ;
if ( ! bitmap ) {
return NULL ;
}
index + + ;
}
/* Search for smallest "large" free block */
best_fit = p = heap - > large_free_buckets [ index + zend_mm_low_bit ( bitmap ) ] ;
while ( ( p = p - > child [ p - > child [ 0 ] ! = NULL ] ) ) {
if ( ZEND_MM_FREE_BLOCK_SIZE ( p ) < ZEND_MM_FREE_BLOCK_SIZE ( best_fit ) ) {
best_fit = p ;
}
}
return best_fit - > next_free_block ;
}
2006-07-18 17:06:33 +08:00
static void * _zend_mm_alloc_int ( zend_mm_heap * heap , size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
2007-03-20 14:46:48 +08:00
zend_mm_free_block * best_fit ;
2006-12-02 04:01:50 +08:00
size_t true_size = ZEND_MM_TRUE_SIZE ( size ) ;
2007-03-20 14:46:48 +08:00
size_t block_size ;
size_t remaining_size ;
size_t segment_size ;
zend_mm_segment * segment ;
2008-02-14 22:42:00 +08:00
int keep_rest = 0 ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
if ( EXPECTED ( ZEND_MM_SMALL_SIZE ( true_size ) ) ) {
2006-07-18 17:06:33 +08:00
size_t index = ZEND_MM_BUCKET_INDEX ( true_size ) ;
2007-03-20 14:46:48 +08:00
size_t bitmap ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( true_size < size ) ) {
goto out_of_memory ;
}
2006-07-18 17:06:33 +08:00
# if ZEND_MM_CACHE
2007-03-20 14:46:48 +08:00
if ( EXPECTED ( heap - > cache [ index ] ! = NULL ) ) {
2006-07-18 17:06:33 +08:00
/* Get block from cache */
2007-03-20 14:46:48 +08:00
# if ZEND_MM_CACHE_STAT
heap - > cache_stat [ index ] . count - - ;
heap - > cache_stat [ index ] . hit + + ;
# endif
2006-07-18 17:06:33 +08:00
best_fit = heap - > cache [ index ] ;
heap - > cache [ index ] = best_fit - > prev_free_block ;
heap - > cached - = true_size ;
ZEND_MM_CHECK_MAGIC ( best_fit , MEM_BLOCK_CACHED ) ;
2006-12-15 21:25:26 +08:00
ZEND_MM_SET_DEBUG_INFO ( best_fit , size , 1 , 0 ) ;
2006-07-18 17:06:33 +08:00
return ZEND_MM_DATA_OF ( best_fit ) ;
2007-03-20 14:46:48 +08:00
}
# if ZEND_MM_CACHE_STAT
heap - > cache_stat [ index ] . miss + + ;
# endif
2006-07-18 17:06:33 +08:00
# endif
bitmap = heap - > free_bitmap > > index ;
if ( bitmap ) {
/* Found some "small" free block that can be used */
2007-03-20 14:46:48 +08:00
index + = zend_mm_low_bit ( bitmap ) ;
best_fit = heap - > free_buckets [ index * 2 ] ;
# if ZEND_MM_CACHE_STAT
heap - > cache_stat [ ZEND_MM_NUM_BUCKETS ] . hit + + ;
# endif
goto zend_mm_finished_searching_for_block ;
2006-07-18 17:06:33 +08:00
}
}
2007-03-20 14:46:48 +08:00
# if ZEND_MM_CACHE_STAT
heap - > cache_stat [ ZEND_MM_NUM_BUCKETS ] . miss + + ;
2006-07-18 17:06:33 +08:00
# endif
2009-01-25 19:07:40 +08:00
best_fit = zend_mm_search_large_block ( heap , true_size ) ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
if ( ! best_fit & & heap - > real_size > = heap - > limit - heap - > block_size ) {
zend_mm_free_block * p = heap - > rest_buckets [ 0 ] ;
size_t best_size = - 1 ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
while ( p ! = ZEND_MM_REST_BUCKET ( heap ) ) {
if ( UNEXPECTED ( ZEND_MM_FREE_BLOCK_SIZE ( p ) = = true_size ) ) {
best_fit = p ;
goto zend_mm_finished_searching_for_block ;
} else if ( ZEND_MM_FREE_BLOCK_SIZE ( p ) > true_size & &
ZEND_MM_FREE_BLOCK_SIZE ( p ) < best_size ) {
best_size = ZEND_MM_FREE_BLOCK_SIZE ( p ) ;
best_fit = p ;
2006-07-18 17:06:33 +08:00
}
2007-03-20 14:46:48 +08:00
p = p - > prev_free_block ;
2006-07-18 17:06:33 +08:00
}
2007-03-20 14:46:48 +08:00
}
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
if ( ! best_fit ) {
2006-12-25 20:16:33 +08:00
if ( true_size > heap - > block_size - ( ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE ) ) {
2006-08-23 21:00:48 +08:00
/* Make sure we add a memory block which is big enough,
segment must have header " size " and trailer " guard " block */
2006-07-18 17:06:33 +08:00
segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE ;
2007-03-20 14:46:48 +08:00
segment_size = ( segment_size + ( heap - > block_size - 1 ) ) & ~ ( heap - > block_size - 1 ) ;
2008-02-14 22:42:00 +08:00
keep_rest = 1 ;
2006-07-18 17:06:33 +08:00
} else {
segment_size = heap - > block_size ;
}
2006-12-05 00:20:02 +08:00
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
2006-07-18 17:06:33 +08:00
2007-03-20 14:46:48 +08:00
if ( segment_size < true_size | |
2006-12-25 20:16:33 +08:00
heap - > real_size + segment_size > heap - > limit ) {
2006-07-18 17:06:33 +08:00
/* Memory limit overflow */
2006-12-05 00:20:02 +08:00
# if ZEND_MM_CACHE
zend_mm_free_cache ( heap ) ;
# endif
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
2006-07-18 17:06:33 +08:00
# if ZEND_DEBUG
2007-05-28 18:07:50 +08:00
zend_mm_safe_error ( heap , " Allowed memory size of %ld bytes exhausted at %s:%d (tried to allocate %lu bytes) " , heap - > limit , __zend_filename , __zend_lineno , size ) ;
2006-07-18 17:06:33 +08:00
# else
2007-05-28 18:07:50 +08:00
zend_mm_safe_error ( heap , " Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes) " , heap - > limit , size ) ;
2006-07-18 17:06:33 +08:00
# endif
}
segment = ( zend_mm_segment * ) ZEND_MM_STORAGE_ALLOC ( segment_size ) ;
if ( ! segment ) {
/* Storage manager cannot allocate memory */
# if ZEND_MM_CACHE
zend_mm_free_cache ( heap ) ;
# endif
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
2006-12-25 20:16:33 +08:00
out_of_memory :
2006-07-18 17:06:33 +08:00
# if ZEND_DEBUG
2007-05-28 18:07:50 +08:00
zend_mm_safe_error ( heap , " Out of memory (allocated %ld) at %s:%d (tried to allocate %lu bytes) " , heap - > real_size , __zend_filename , __zend_lineno , size ) ;
2006-07-18 17:06:33 +08:00
# else
2007-05-28 18:07:50 +08:00
zend_mm_safe_error ( heap , " Out of memory (allocated %ld) (tried to allocate %lu bytes) " , heap - > real_size , size ) ;
2006-07-18 17:06:33 +08:00
# endif
return NULL ;
}
2006-07-25 21:40:05 +08:00
heap - > real_size + = segment_size ;
if ( heap - > real_size > heap - > real_peak ) {
heap - > real_peak = heap - > real_size ;
2006-07-18 17:06:33 +08:00
}
segment - > size = segment_size ;
segment - > next_segment = heap - > segments_list ;
heap - > segments_list = segment ;
best_fit = ( zend_mm_free_block * ) ( ( char * ) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
ZEND_MM_MARK_FIRST_BLOCK ( best_fit ) ;
2006-08-23 21:00:48 +08:00
block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE ;
ZEND_MM_LAST_BLOCK ( ZEND_MM_BLOCK_AT ( best_fit , block_size ) ) ;
2007-03-20 14:46:48 +08:00
} else {
zend_mm_finished_searching_for_block :
/* remove from free list */
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
ZEND_MM_CHECK_MAGIC ( best_fit , MEM_BLOCK_FREED ) ;
ZEND_MM_CHECK_COOKIE ( best_fit ) ;
ZEND_MM_CHECK_BLOCK_LINKAGE ( best_fit ) ;
zend_mm_remove_from_free_list ( heap , best_fit ) ;
2006-08-23 21:00:48 +08:00
2007-03-20 14:46:48 +08:00
block_size = ZEND_MM_FREE_BLOCK_SIZE ( best_fit ) ;
}
2006-08-23 21:00:48 +08:00
2007-03-20 14:46:48 +08:00
remaining_size = block_size - true_size ;
if ( remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE ) {
true_size = block_size ;
ZEND_MM_BLOCK ( best_fit , ZEND_MM_USED_BLOCK , true_size ) ;
} else {
zend_mm_free_block * new_free_block ;
/* prepare new free block */
ZEND_MM_BLOCK ( best_fit , ZEND_MM_USED_BLOCK , true_size ) ;
new_free_block = ( zend_mm_free_block * ) ZEND_MM_BLOCK_AT ( best_fit , true_size ) ;
ZEND_MM_BLOCK ( new_free_block , ZEND_MM_FREE_BLOCK , remaining_size ) ;
/* add the new free block to the free list */
2008-02-14 22:42:00 +08:00
if ( EXPECTED ( ! keep_rest ) ) {
zend_mm_add_to_free_list ( heap , new_free_block ) ;
} else {
zend_mm_add_to_rest_list ( heap , new_free_block ) ;
}
2006-07-18 17:06:33 +08:00
}
2006-12-15 21:25:26 +08:00
ZEND_MM_SET_DEBUG_INFO ( best_fit , size , 1 , 1 ) ;
2006-07-25 21:40:05 +08:00
heap - > size + = true_size ;
if ( heap - > peak < heap - > size ) {
heap - > peak = heap - > size ;
}
2006-07-18 17:06:33 +08:00
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
return ZEND_MM_DATA_OF ( best_fit ) ;
}
static void _zend_mm_free_int ( zend_mm_heap * heap , void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
zend_mm_block * mm_block ;
2007-03-20 14:46:48 +08:00
zend_mm_block * next_block ;
2006-07-18 17:06:33 +08:00
size_t size ;
if ( ! ZEND_MM_VALID_PTR ( p ) ) {
return ;
}
2007-02-17 02:06:28 +08:00
2006-07-18 17:06:33 +08:00
mm_block = ZEND_MM_HEADER_OF ( p ) ;
size = ZEND_MM_BLOCK_SIZE ( mm_block ) ;
2006-12-15 21:25:26 +08:00
ZEND_MM_CHECK_PROTECTION ( mm_block ) ;
2006-07-18 17:06:33 +08:00
2006-12-15 21:25:26 +08:00
# if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2006-07-18 17:06:33 +08:00
memset ( ZEND_MM_DATA_OF ( mm_block ) , 0x5a , mm_block - > debug . size ) ;
# endif
# if ZEND_MM_CACHE
2007-03-20 14:46:48 +08:00
if ( EXPECTED ( ZEND_MM_SMALL_SIZE ( size ) ) & & EXPECTED ( heap - > cached < ZEND_MM_CACHE_SIZE ) ) {
2006-07-18 17:06:33 +08:00
size_t index = ZEND_MM_BUCKET_INDEX ( size ) ;
zend_mm_free_block * * cache = & heap - > cache [ index ] ;
( ( zend_mm_free_block * ) mm_block ) - > prev_free_block = * cache ;
* cache = ( zend_mm_free_block * ) mm_block ;
heap - > cached + = size ;
ZEND_MM_SET_MAGIC ( mm_block , MEM_BLOCK_CACHED ) ;
2007-03-20 14:46:48 +08:00
# if ZEND_MM_CACHE_STAT
if ( + + heap - > cache_stat [ index ] . count > heap - > cache_stat [ index ] . max_count ) {
heap - > cache_stat [ index ] . max_count = heap - > cache_stat [ index ] . count ;
}
# endif
2006-07-18 17:06:33 +08:00
return ;
}
# endif
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
2006-07-25 21:40:05 +08:00
heap - > size - = size ;
2007-03-20 14:46:48 +08:00
next_block = ZEND_MM_BLOCK_AT ( mm_block , size ) ;
if ( ZEND_MM_IS_FREE_BLOCK ( next_block ) ) {
zend_mm_remove_from_free_list ( heap , ( zend_mm_free_block * ) next_block ) ;
size + = ZEND_MM_FREE_BLOCK_SIZE ( next_block ) ;
}
2006-07-18 17:06:33 +08:00
if ( ZEND_MM_PREV_BLOCK_IS_FREE ( mm_block ) ) {
2007-03-20 14:46:48 +08:00
mm_block = ZEND_MM_PREV_BLOCK ( mm_block ) ;
zend_mm_remove_from_free_list ( heap , ( zend_mm_free_block * ) mm_block ) ;
size + = ZEND_MM_FREE_BLOCK_SIZE ( mm_block ) ;
2006-07-18 17:06:33 +08:00
}
if ( ZEND_MM_IS_FIRST_BLOCK ( mm_block ) & &
2007-03-20 14:46:48 +08:00
ZEND_MM_IS_GUARD_BLOCK ( ZEND_MM_BLOCK_AT ( mm_block , size ) ) ) {
2006-07-18 17:06:33 +08:00
zend_mm_del_segment ( heap , ( zend_mm_segment * ) ( ( char * ) mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE ) ) ;
} else {
2007-03-20 14:46:48 +08:00
ZEND_MM_BLOCK ( mm_block , ZEND_MM_FREE_BLOCK , size ) ;
2006-07-18 17:06:33 +08:00
zend_mm_add_to_free_list ( heap , ( zend_mm_free_block * ) mm_block ) ;
}
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
}
static void * _zend_mm_realloc_int ( zend_mm_heap * heap , void * p , size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
zend_mm_block * mm_block = ZEND_MM_HEADER_OF ( p ) ;
zend_mm_block * next_block ;
size_t true_size ;
2006-12-01 19:42:20 +08:00
size_t orig_size ;
2006-07-18 17:06:33 +08:00
void * ptr ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( ! p ) | | ! ZEND_MM_VALID_PTR ( p ) ) {
2006-07-18 17:06:33 +08:00
return _zend_mm_alloc_int ( heap , size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
mm_block = ZEND_MM_HEADER_OF ( p ) ;
true_size = ZEND_MM_TRUE_SIZE ( size ) ;
2006-12-01 19:42:20 +08:00
orig_size = ZEND_MM_BLOCK_SIZE ( mm_block ) ;
2006-12-15 21:25:26 +08:00
ZEND_MM_CHECK_PROTECTION ( mm_block ) ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( true_size < size ) ) {
2006-12-25 20:16:33 +08:00
goto out_of_memory ;
}
2006-12-01 19:42:20 +08:00
if ( true_size < = orig_size ) {
size_t remaining_size = orig_size - true_size ;
2006-07-18 17:06:33 +08:00
if ( remaining_size > = ZEND_MM_ALIGNED_MIN_HEADER_SIZE ) {
zend_mm_free_block * new_free_block ;
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
2007-03-20 14:46:48 +08:00
next_block = ZEND_MM_BLOCK_AT ( mm_block , orig_size ) ;
2006-07-18 17:06:33 +08:00
if ( ZEND_MM_IS_FREE_BLOCK ( next_block ) ) {
remaining_size + = ZEND_MM_FREE_BLOCK_SIZE ( next_block ) ;
zend_mm_remove_from_free_list ( heap , ( zend_mm_free_block * ) next_block ) ;
}
/* prepare new free block */
ZEND_MM_BLOCK ( mm_block , ZEND_MM_USED_BLOCK , true_size ) ;
new_free_block = ( zend_mm_free_block * ) ZEND_MM_BLOCK_AT ( mm_block , true_size ) ;
ZEND_MM_BLOCK ( new_free_block , ZEND_MM_FREE_BLOCK , remaining_size ) ;
/* add the new free block to the free list */
zend_mm_add_to_free_list ( heap , new_free_block ) ;
2006-12-01 19:42:20 +08:00
heap - > size + = ( true_size - orig_size ) ;
2006-07-18 17:06:33 +08:00
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
}
2006-12-15 21:25:26 +08:00
ZEND_MM_SET_DEBUG_INFO ( mm_block , size , 0 , 0 ) ;
2006-07-18 17:06:33 +08:00
return p ;
}
2007-03-23 15:59:26 +08:00
# if ZEND_MM_CACHE
if ( ZEND_MM_SMALL_SIZE ( true_size ) ) {
size_t index = ZEND_MM_BUCKET_INDEX ( true_size ) ;
if ( heap - > cache [ index ] ! = NULL ) {
zend_mm_free_block * best_fit ;
zend_mm_free_block * * cache ;
# if ZEND_MM_CACHE_STAT
heap - > cache_stat [ index ] . count - - ;
heap - > cache_stat [ index ] . hit + + ;
# endif
best_fit = heap - > cache [ index ] ;
heap - > cache [ index ] = best_fit - > prev_free_block ;
ZEND_MM_CHECK_MAGIC ( best_fit , MEM_BLOCK_CACHED ) ;
ZEND_MM_SET_DEBUG_INFO ( best_fit , size , 1 , 0 ) ;
ptr = ZEND_MM_DATA_OF ( best_fit ) ;
# if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
memcpy ( ptr , p , mm_block - > debug . size ) ;
# else
memcpy ( ptr , p , orig_size - ZEND_MM_ALIGNED_HEADER_SIZE ) ;
# endif
heap - > cached - = true_size - orig_size ;
index = ZEND_MM_BUCKET_INDEX ( orig_size ) ;
cache = & heap - > cache [ index ] ;
( ( zend_mm_free_block * ) mm_block ) - > prev_free_block = * cache ;
* cache = ( zend_mm_free_block * ) mm_block ;
ZEND_MM_SET_MAGIC ( mm_block , MEM_BLOCK_CACHED ) ;
# if ZEND_MM_CACHE_STAT
if ( + + heap - > cache_stat [ index ] . count > heap - > cache_stat [ index ] . max_count ) {
heap - > cache_stat [ index ] . max_count = heap - > cache_stat [ index ] . count ;
}
# endif
return ptr ;
}
}
# endif
2007-03-20 14:46:48 +08:00
next_block = ZEND_MM_BLOCK_AT ( mm_block , orig_size ) ;
2006-07-18 17:06:33 +08:00
if ( ZEND_MM_IS_FREE_BLOCK ( next_block ) ) {
2006-12-15 21:25:26 +08:00
ZEND_MM_CHECK_COOKIE ( next_block ) ;
ZEND_MM_CHECK_BLOCK_LINKAGE ( next_block ) ;
2006-12-01 19:42:20 +08:00
if ( orig_size + ZEND_MM_FREE_BLOCK_SIZE ( next_block ) > = true_size ) {
size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE ( next_block ) ;
2006-07-18 17:06:33 +08:00
size_t remaining_size = block_size - true_size ;
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
zend_mm_remove_from_free_list ( heap , ( zend_mm_free_block * ) next_block ) ;
if ( remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE ) {
2006-12-01 19:42:20 +08:00
true_size = block_size ;
2007-03-20 14:46:48 +08:00
ZEND_MM_BLOCK ( mm_block , ZEND_MM_USED_BLOCK , true_size ) ;
2006-07-18 17:06:33 +08:00
} else {
zend_mm_free_block * new_free_block ;
/* prepare new free block */
ZEND_MM_BLOCK ( mm_block , ZEND_MM_USED_BLOCK , true_size ) ;
new_free_block = ( zend_mm_free_block * ) ZEND_MM_BLOCK_AT ( mm_block , true_size ) ;
ZEND_MM_BLOCK ( new_free_block , ZEND_MM_FREE_BLOCK , remaining_size ) ;
/* add the new free block to the free list */
2007-03-20 14:46:48 +08:00
if ( ZEND_MM_IS_FIRST_BLOCK ( mm_block ) & &
ZEND_MM_IS_GUARD_BLOCK ( ZEND_MM_BLOCK_AT ( new_free_block , remaining_size ) ) ) {
zend_mm_add_to_rest_list ( heap , new_free_block ) ;
} else {
zend_mm_add_to_free_list ( heap , new_free_block ) ;
}
2006-07-18 17:06:33 +08:00
}
2006-12-15 21:25:26 +08:00
ZEND_MM_SET_DEBUG_INFO ( mm_block , size , 0 , 0 ) ;
2006-12-01 19:42:20 +08:00
heap - > size = heap - > size + true_size - orig_size ;
if ( heap - > peak < heap - > size ) {
heap - > peak = heap - > size ;
}
2006-07-18 17:06:33 +08:00
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
return p ;
} else if ( ZEND_MM_IS_FIRST_BLOCK ( mm_block ) & &
2007-03-20 14:46:48 +08:00
ZEND_MM_IS_GUARD_BLOCK ( ZEND_MM_BLOCK_AT ( next_block , ZEND_MM_FREE_BLOCK_SIZE ( next_block ) ) ) ) {
2006-07-18 17:06:33 +08:00
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
zend_mm_remove_from_free_list ( heap , ( zend_mm_free_block * ) next_block ) ;
goto realloc_segment ;
}
} else if ( ZEND_MM_IS_FIRST_BLOCK ( mm_block ) & & ZEND_MM_IS_GUARD_BLOCK ( next_block ) ) {
zend_mm_segment * segment ;
zend_mm_segment * segment_copy ;
size_t segment_size ;
2006-08-23 21:00:48 +08:00
size_t block_size ;
size_t remaining_size ;
2006-07-18 17:06:33 +08:00
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
realloc_segment :
/* segment size, size of block and size of guard block */
2006-12-25 20:16:33 +08:00
if ( true_size > heap - > block_size - ( ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE ) ) {
2006-07-18 17:06:33 +08:00
segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE ;
2007-03-20 14:46:48 +08:00
segment_size = ( segment_size + ( heap - > block_size - 1 ) ) & ~ ( heap - > block_size - 1 ) ;
2006-07-18 17:06:33 +08:00
} else {
segment_size = heap - > block_size ;
}
segment_copy = ( zend_mm_segment * ) ( ( char * ) mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
2006-12-25 20:16:33 +08:00
if ( segment_size < true_size | |
heap - > real_size + segment_size - segment_copy - > size > heap - > limit ) {
2007-03-13 00:59:52 +08:00
if ( ZEND_MM_IS_FREE_BLOCK ( next_block ) ) {
zend_mm_add_to_free_list ( heap , ( zend_mm_free_block * ) next_block ) ;
}
2006-12-05 00:20:02 +08:00
# if ZEND_MM_CACHE
zend_mm_free_cache ( heap ) ;
# endif
2006-07-18 17:06:33 +08:00
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
# if ZEND_DEBUG
2007-03-20 14:46:48 +08:00
zend_mm_safe_error ( heap , " Allowed memory size of %ld bytes exhausted at %s:%d (tried to allocate %ld bytes) " , heap - > limit , __zend_filename , __zend_lineno , size ) ;
2006-07-18 17:06:33 +08:00
# else
2007-03-20 14:46:48 +08:00
zend_mm_safe_error ( heap , " Allowed memory size of %ld bytes exhausted (tried to allocate %ld bytes) " , heap - > limit , size ) ;
2006-07-18 17:06:33 +08:00
# endif
return NULL ;
}
2007-03-20 14:46:48 +08:00
2006-07-18 17:06:33 +08:00
segment = ZEND_MM_STORAGE_REALLOC ( segment_copy , segment_size ) ;
if ( ! segment ) {
2006-12-05 00:20:02 +08:00
# if ZEND_MM_CACHE
zend_mm_free_cache ( heap ) ;
# endif
2006-07-18 17:06:33 +08:00
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
2006-12-25 20:16:33 +08:00
out_of_memory :
2006-07-18 17:06:33 +08:00
# if ZEND_DEBUG
2007-03-20 14:46:48 +08:00
zend_mm_safe_error ( heap , " Out of memory (allocated %ld) at %s:%d (tried to allocate %ld bytes) " , heap - > real_size , __zend_filename , __zend_lineno , size ) ;
2006-07-18 17:06:33 +08:00
# else
2007-03-20 14:46:48 +08:00
zend_mm_safe_error ( heap , " Out of memory (allocated %ld) (tried to allocate %ld bytes) " , heap - > real_size , size ) ;
2006-07-18 17:06:33 +08:00
# endif
return NULL ;
}
2006-07-25 21:40:05 +08:00
heap - > real_size + = segment_size - segment - > size ;
if ( heap - > real_size > heap - > real_peak ) {
heap - > real_peak = heap - > real_size ;
2006-07-18 17:06:33 +08:00
}
2006-12-20 18:49:33 +08:00
2006-07-18 17:06:33 +08:00
segment - > size = segment_size ;
if ( segment ! = segment_copy ) {
2007-03-20 14:46:48 +08:00
zend_mm_segment * * seg = & heap - > segments_list ;
while ( * seg ! = segment_copy ) {
seg = & ( * seg ) - > next_segment ;
2006-07-18 17:06:33 +08:00
}
2007-03-20 14:46:48 +08:00
* seg = segment ;
2006-07-18 17:06:33 +08:00
mm_block = ( zend_mm_block * ) ( ( char * ) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE ) ;
2006-08-23 21:00:48 +08:00
ZEND_MM_MARK_FIRST_BLOCK ( mm_block ) ;
2006-07-18 17:06:33 +08:00
}
2006-08-23 21:00:48 +08:00
block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE ;
remaining_size = block_size - true_size ;
2006-07-18 17:06:33 +08:00
2006-08-23 21:00:48 +08:00
/* setup guard block */
ZEND_MM_LAST_BLOCK ( ZEND_MM_BLOCK_AT ( mm_block , block_size ) ) ;
if ( remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE ) {
2006-12-01 19:42:20 +08:00
true_size = block_size ;
ZEND_MM_BLOCK ( mm_block , ZEND_MM_USED_BLOCK , true_size ) ;
2006-08-23 21:00:48 +08:00
} else {
zend_mm_free_block * new_free_block ;
/* prepare new free block */
ZEND_MM_BLOCK ( mm_block , ZEND_MM_USED_BLOCK , true_size ) ;
new_free_block = ( zend_mm_free_block * ) ZEND_MM_BLOCK_AT ( mm_block , true_size ) ;
ZEND_MM_BLOCK ( new_free_block , ZEND_MM_FREE_BLOCK , remaining_size ) ;
/* add the new free block to the free list */
2007-03-20 14:46:48 +08:00
zend_mm_add_to_rest_list ( heap , new_free_block ) ;
2006-07-18 17:06:33 +08:00
}
2006-12-15 21:25:26 +08:00
ZEND_MM_SET_DEBUG_INFO ( mm_block , size , 1 , 1 ) ;
2006-12-20 18:49:33 +08:00
2006-12-01 19:42:20 +08:00
heap - > size = heap - > size + true_size - orig_size ;
if ( heap - > peak < heap - > size ) {
heap - > peak = heap - > size ;
}
2006-12-20 18:49:33 +08:00
2006-07-18 17:06:33 +08:00
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
return ZEND_MM_DATA_OF ( mm_block ) ;
}
ptr = _zend_mm_alloc_int ( heap , size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
2006-12-15 21:25:26 +08:00
# if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2006-07-18 17:06:33 +08:00
memcpy ( ptr , p , mm_block - > debug . size ) ;
# else
2006-12-01 19:42:20 +08:00
memcpy ( ptr , p , orig_size - ZEND_MM_ALIGNED_HEADER_SIZE ) ;
2006-07-18 17:06:33 +08:00
# endif
_zend_mm_free_int ( heap , p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
return ptr ;
}
ZEND_API void * _zend_mm_alloc ( zend_mm_heap * heap , size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
return _zend_mm_alloc_int ( heap , size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
ZEND_API void _zend_mm_free ( zend_mm_heap * heap , void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
_zend_mm_free_int ( heap , p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
ZEND_API void * _zend_mm_realloc ( zend_mm_heap * heap , void * ptr , size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
return _zend_mm_realloc_int ( heap , ptr , size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
ZEND_API size_t _zend_mm_block_size ( zend_mm_heap * heap , void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
zend_mm_block * mm_block ;
if ( ! ZEND_MM_VALID_PTR ( p ) ) {
return 0 ;
}
mm_block = ZEND_MM_HEADER_OF ( p ) ;
2006-12-15 21:25:26 +08:00
ZEND_MM_CHECK_PROTECTION ( mm_block ) ;
# if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2006-07-18 17:06:33 +08:00
return mm_block - > debug . size ;
# else
return ZEND_MM_BLOCK_SIZE ( mm_block ) ;
# endif
}
/**********************/
/* Allocation Manager */
/**********************/
typedef struct _zend_alloc_globals {
zend_mm_heap * mm_heap ;
} zend_alloc_globals ;
# ifdef ZTS
static int alloc_globals_id ;
# define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v)
# else
# define AG(v) (alloc_globals.v)
static zend_alloc_globals alloc_globals ;
# endif
2006-09-14 16:00:44 +08:00
ZEND_API int is_zend_mm ( TSRMLS_D )
{
return AG ( mm_heap ) - > use_zend_alloc ;
}
2006-07-18 17:06:33 +08:00
ZEND_API void * _emalloc ( size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
TSRMLS_FETCH ( ) ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( ! AG ( mm_heap ) - > use_zend_alloc ) ) {
2007-11-06 20:06:05 +08:00
return AG ( mm_heap ) - > _malloc ( size ) ;
2006-07-18 17:06:33 +08:00
}
return _zend_mm_alloc_int ( AG ( mm_heap ) , size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
ZEND_API void _efree ( void * ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
TSRMLS_FETCH ( ) ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( ! AG ( mm_heap ) - > use_zend_alloc ) ) {
2007-11-06 20:06:05 +08:00
AG ( mm_heap ) - > _free ( ptr ) ;
2006-07-18 17:06:33 +08:00
return ;
}
_zend_mm_free_int ( AG ( mm_heap ) , ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
ZEND_API void * _erealloc ( void * ptr , size_t size , int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
1999-04-08 02:10:10 +08:00
{
2001-07-28 18:51:54 +08:00
TSRMLS_FETCH ( ) ;
1999-04-08 02:10:10 +08:00
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( ! AG ( mm_heap ) - > use_zend_alloc ) ) {
2007-11-06 20:06:05 +08:00
return AG ( mm_heap ) - > _realloc ( ptr , size ) ;
1999-04-08 02:10:10 +08:00
}
2006-07-18 17:06:33 +08:00
return _zend_mm_realloc_int ( AG ( mm_heap ) , ptr , size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
}
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
ZEND_API size_t _zend_mem_block_size ( void * ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( ! AG ( mm_heap ) - > use_zend_alloc ) ) {
2006-07-18 17:06:33 +08:00
return 0 ;
1999-04-08 02:10:10 +08:00
}
2006-07-18 17:06:33 +08:00
return _zend_mm_block_size ( AG ( mm_heap ) , ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
1999-04-08 02:10:10 +08:00
}
2007-03-20 14:46:48 +08:00
# if defined(__GNUC__) && defined(i386)
2003-04-24 11:35:06 +08:00
2007-03-20 14:46:48 +08:00
static inline size_t safe_address ( size_t nmemb , size_t size , size_t offset )
2003-04-24 11:35:06 +08:00
{
2007-03-20 14:46:48 +08:00
size_t res = nmemb ;
2007-12-20 20:58:46 +08:00
unsigned long overflow = 0 ;
2007-03-20 14:46:48 +08:00
2007-12-20 20:58:46 +08:00
__asm__ ( " mull %3 \n \t addl %4,%0 \n \t adcl %1,%1 "
: " =&a " ( res ) , " =&d " ( overflow )
2007-03-20 14:46:48 +08:00
: " %0 " ( res ) ,
" rm " ( size ) ,
" rm " ( offset ) ) ;
if ( UNEXPECTED ( overflow ) ) {
2007-05-28 18:07:50 +08:00
zend_error_noreturn ( E_ERROR , " Possible integer overflow in memory allocation (%zu * %zu + %zu) " , nmemb , size , offset ) ;
2007-03-20 14:46:48 +08:00
return 0 ;
}
return res ;
}
2003-04-24 11:35:06 +08:00
2007-12-20 20:58:46 +08:00
# elif defined(__GNUC__) && defined(__x86_64__)
static inline size_t safe_address ( size_t nmemb , size_t size , size_t offset )
{
size_t res = nmemb ;
unsigned long overflow = 0 ;
__asm__ ( " mulq %3 \n \t addq %4,%0 \n \t adcq %1,%1 "
: " =&a " ( res ) , " =&d " ( overflow )
: " %0 " ( res ) ,
" rm " ( size ) ,
" rm " ( offset ) ) ;
if ( UNEXPECTED ( overflow ) ) {
zend_error_noreturn ( E_ERROR , " Possible integer overflow in memory allocation (%zu * %zu + %zu) " , nmemb , size , offset ) ;
return 0 ;
}
return res ;
}
2008-07-24 21:46:28 +08:00
# elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64)
static inline size_t safe_address ( size_t nmemb , size_t size , size_t offset )
{
zend_ulong64 res = ( zend_ulong64 ) nmemb * ( zend_ulong64 ) size + ( zend_ulong64 ) offset ;
if ( UNEXPECTED ( res > ( zend_ulong64 ) 0xFFFFFFFFL ) ) {
zend_error_noreturn ( E_ERROR , " Possible integer overflow in memory allocation (%zu * %zu + %zu) " , nmemb , size , offset ) ;
return 0 ;
}
return ( size_t ) res ;
}
2007-03-20 14:46:48 +08:00
# else
2003-04-24 11:35:06 +08:00
2007-03-20 14:46:48 +08:00
static inline size_t safe_address ( size_t nmemb , size_t size , size_t offset )
{
size_t res = nmemb * size + offset ;
double _d = ( double ) nmemb * ( double ) size + ( double ) offset ;
double _delta = ( double ) res - _d ;
2003-04-24 11:35:06 +08:00
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( ( _d + _delta ) ! = _d ) ) {
2007-05-28 18:07:50 +08:00
zend_error_noreturn ( E_ERROR , " Possible integer overflow in memory allocation (%zu * %zu + %zu) " , nmemb , size , offset ) ;
2007-03-20 14:46:48 +08:00
return 0 ;
2003-04-24 11:35:06 +08:00
}
2007-03-20 14:46:48 +08:00
return res ;
}
# endif
2003-04-24 11:35:06 +08:00
2007-03-20 14:46:48 +08:00
ZEND_API void * _safe_emalloc ( size_t nmemb , size_t size , size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
return emalloc_rel ( safe_address ( nmemb , size , offset ) ) ;
2003-04-24 11:35:06 +08:00
}
2004-07-21 05:55:57 +08:00
ZEND_API void * _safe_malloc ( size_t nmemb , size_t size , size_t offset )
{
2007-03-20 14:46:48 +08:00
return pemalloc ( safe_address ( nmemb , size , offset ) , 1 ) ;
2004-07-21 05:55:57 +08:00
}
2003-04-24 11:35:06 +08:00
2007-02-17 02:06:28 +08:00
ZEND_API void * _safe_erealloc ( void * ptr , size_t nmemb , size_t size , size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
2007-03-20 14:46:48 +08:00
return erealloc_rel ( ptr , safe_address ( nmemb , size , offset ) ) ;
2007-02-17 02:06:28 +08:00
}
ZEND_API void * _safe_realloc ( void * ptr , size_t nmemb , size_t size , size_t offset )
{
2007-03-20 14:46:48 +08:00
return perealloc ( ptr , safe_address ( nmemb , size , offset ) , 1 ) ;
2007-02-17 02:06:28 +08:00
}
2002-04-28 14:24:15 +08:00
ZEND_API void * _ecalloc ( size_t nmemb , size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
{
void * p ;
2006-07-18 17:06:33 +08:00
2006-10-01 01:12:06 +08:00
p = _safe_emalloc ( nmemb , size , 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( p = = NULL ) ) {
return p ;
2002-04-28 14:24:15 +08:00
}
2006-10-01 01:12:06 +08:00
memset ( p , 0 , size * nmemb ) ;
2002-04-28 14:24:15 +08:00
return p ;
}
1999-08-28 18:18:54 +08:00
ZEND_API char * _estrdup ( const char * s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
1999-04-08 02:10:10 +08:00
{
int length ;
char * p ;
length = strlen ( s ) + 1 ;
1999-08-28 18:18:54 +08:00
p = ( char * ) _emalloc ( length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( p = = NULL ) ) {
return p ;
1999-04-08 02:10:10 +08:00
}
2001-04-28 23:59:39 +08:00
memcpy ( p , s , length ) ;
1999-04-08 02:10:10 +08:00
return p ;
}
1999-08-28 18:18:54 +08:00
ZEND_API char * _estrndup ( const char * s , uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
1999-04-08 02:10:10 +08:00
{
char * p ;
1999-08-28 18:18:54 +08:00
p = ( char * ) _emalloc ( length + 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( p = = NULL ) ) {
return p ;
1999-04-08 02:10:10 +08:00
}
2001-04-28 23:59:39 +08:00
memcpy ( p , s , length ) ;
p [ length ] = 0 ;
1999-04-08 02:10:10 +08:00
return p ;
}
ZEND_API char * zend_strndup ( const char * s , uint length )
{
char * p ;
p = ( char * ) malloc ( length + 1 ) ;
2007-03-20 14:46:48 +08:00
if ( UNEXPECTED ( p = = NULL ) ) {
return p ;
1999-04-08 02:10:10 +08:00
}
if ( length ) {
2001-04-28 23:59:39 +08:00
memcpy ( p , s , length ) ;
1999-04-08 02:10:10 +08:00
}
2001-04-28 23:59:39 +08:00
p [ length ] = 0 ;
1999-04-08 02:10:10 +08:00
return p ;
}
2007-03-14 19:58:05 +08:00
ZEND_API int zend_set_memory_limit ( size_t memory_limit )
1999-04-10 22:44:35 +08:00
{
2001-07-28 18:51:54 +08:00
TSRMLS_FETCH ( ) ;
1999-04-10 22:44:35 +08:00
2007-03-20 14:46:48 +08:00
AG ( mm_heap ) - > limit = ( memory_limit > = AG ( mm_heap ) - > block_size ) ? memory_limit : AG ( mm_heap ) - > block_size ;
1999-04-10 22:44:35 +08:00
return SUCCESS ;
}
2006-07-25 21:40:05 +08:00
ZEND_API size_t zend_memory_usage ( int real_usage TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
2006-07-25 21:40:05 +08:00
if ( real_usage ) {
return AG ( mm_heap ) - > real_size ;
} else {
return AG ( mm_heap ) - > size ;
}
1999-04-08 02:10:10 +08:00
}
2006-07-25 21:40:05 +08:00
ZEND_API size_t zend_memory_peak_usage ( int real_usage TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
2006-07-25 21:40:05 +08:00
if ( real_usage ) {
return AG ( mm_heap ) - > real_peak ;
} else {
return AG ( mm_heap ) - > peak ;
}
2006-10-12 14:46:51 +08:00
}
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
ZEND_API void shutdown_memory_manager ( int silent , int full_shutdown TSRMLS_DC )
{
2008-08-16 03:47:33 +08:00
zend_mm_shutdown ( AG ( mm_heap ) , full_shutdown , silent TSRMLS_CC ) ;
2006-07-18 17:06:33 +08:00
}
2002-06-26 19:07:35 +08:00
2006-07-18 17:06:33 +08:00
static void alloc_globals_ctor ( zend_alloc_globals * alloc_globals TSRMLS_DC )
{
2006-12-20 18:49:33 +08:00
char * tmp ;
2006-07-18 17:06:33 +08:00
alloc_globals - > mm_heap = zend_mm_startup ( ) ;
2007-03-20 14:46:48 +08:00
2006-12-20 18:49:33 +08:00
tmp = getenv ( " USE_ZEND_ALLOC " ) ;
if ( tmp ) {
alloc_globals - > mm_heap - > use_zend_alloc = zend_atoi ( tmp , 0 ) ;
2007-11-06 15:22:13 +08:00
if ( ! alloc_globals - > mm_heap - > use_zend_alloc ) {
2007-11-06 20:06:05 +08:00
alloc_globals - > mm_heap - > _malloc = malloc ;
alloc_globals - > mm_heap - > _free = free ;
alloc_globals - > mm_heap - > _realloc = realloc ;
2007-11-06 15:22:13 +08:00
}
1999-04-08 02:10:10 +08:00
}
2006-07-18 17:06:33 +08:00
}
2001-08-03 15:06:05 +08:00
2006-07-18 17:06:33 +08:00
# ifdef ZTS
static void alloc_globals_dtor ( zend_alloc_globals * alloc_globals TSRMLS_DC )
{
shutdown_memory_manager ( 1 , 1 TSRMLS_CC ) ;
}
2002-06-24 15:22:25 +08:00
# endif
2002-06-25 02:49:13 +08:00
2006-07-18 17:06:33 +08:00
ZEND_API void start_memory_manager ( TSRMLS_D )
{
# ifdef ZTS
ts_allocate_id ( & alloc_globals_id , sizeof ( zend_alloc_globals ) , ( ts_allocate_ctor ) alloc_globals_ctor , ( ts_allocate_dtor ) alloc_globals_dtor ) ;
# else
alloc_globals_ctor ( & alloc_globals ) ;
1999-12-28 00:42:59 +08:00
# endif
1999-04-08 02:10:10 +08:00
}
2006-07-18 17:06:33 +08:00
ZEND_API zend_mm_heap * zend_mm_set_heap ( zend_mm_heap * new_heap TSRMLS_DC )
1999-05-12 05:38:39 +08:00
{
2006-07-18 17:06:33 +08:00
zend_mm_heap * old_heap ;
1999-05-12 05:38:39 +08:00
2006-07-18 17:06:33 +08:00
old_heap = AG ( mm_heap ) ;
AG ( mm_heap ) = new_heap ;
return old_heap ;
1999-05-12 05:38:39 +08:00
}
2007-03-20 14:46:48 +08:00
ZEND_API zend_mm_storage * zend_mm_get_storage ( zend_mm_heap * heap )
{
return heap - > storage ;
}
1999-05-12 05:38:39 +08:00
2007-11-06 15:22:13 +08:00
ZEND_API void zend_mm_set_custom_handlers ( zend_mm_heap * heap ,
2007-11-06 20:06:05 +08:00
void * ( * _malloc ) ( size_t ) ,
void ( * _free ) ( void * ) ,
void * ( * _realloc ) ( void * , size_t ) )
2007-11-06 15:22:13 +08:00
{
heap - > use_zend_alloc = 0 ;
2007-11-06 20:06:05 +08:00
heap - > _malloc = _malloc ;
heap - > _free = _free ;
heap - > _realloc = _realloc ;
2007-11-06 15:22:13 +08:00
}
2006-07-18 17:06:33 +08:00
# if ZEND_DEBUG
1999-08-28 18:18:54 +08:00
ZEND_API int _mem_block_check ( void * ptr , int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
1999-04-08 02:10:10 +08:00
{
2006-07-18 17:06:33 +08:00
TSRMLS_FETCH ( ) ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
if ( ! AG ( mm_heap ) - > use_zend_alloc ) {
return 1 ;
1999-04-08 02:10:10 +08:00
}
2006-07-18 17:06:33 +08:00
return zend_mm_check_ptr ( AG ( mm_heap ) , ptr , silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
1999-04-08 02:10:10 +08:00
}
1999-08-28 18:18:54 +08:00
ZEND_API void _full_mem_check ( int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC )
1999-04-08 02:10:10 +08:00
{
2006-07-18 17:06:33 +08:00
int errors ;
2001-07-28 18:51:54 +08:00
TSRMLS_FETCH ( ) ;
1999-04-21 11:49:09 +08:00
2006-07-18 17:06:33 +08:00
if ( ! AG ( mm_heap ) - > use_zend_alloc ) {
return ;
}
1999-04-08 02:10:10 +08:00
1999-05-12 05:38:39 +08:00
zend_debug_alloc_output ( " ------------------------------------------------ \n " ) ;
1999-08-28 03:17:19 +08:00
zend_debug_alloc_output ( " Full Memory Check at %s:%d \n " ZEND_FILE_LINE_RELAY_CC ) ;
1999-04-08 02:10:10 +08:00
2006-07-18 17:06:33 +08:00
errors = zend_mm_check_heap ( AG ( mm_heap ) , silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC ) ;
1999-08-28 03:17:19 +08:00
zend_debug_alloc_output ( " End of full memory check %s:%d (%d errors) \n " ZEND_FILE_LINE_RELAY_CC , errors ) ;
1999-05-12 05:38:39 +08:00
zend_debug_alloc_output ( " ------------------------------------------------ \n " ) ;
1999-04-08 02:10:10 +08:00
}
# endif
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
2003-02-01 09:49:15 +08:00
* indent - tabs - mode : t
1999-04-08 02:10:10 +08:00
* End :
*/