diff options
Diffstat (limited to 'Zend/zend_alloc.c')
-rw-r--r-- | Zend/zend_alloc.c | 171 |
1 files changed, 99 insertions, 72 deletions
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 11f5b46bd9..3531e79df4 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | Zend Engine | +----------------------------------------------------------------------+ - | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) | + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | @@ -57,10 +57,8 @@ #include "zend_operators.h" #include "zend_multiply.h" #include "zend_bitset.h" +#include <signal.h> -#ifdef HAVE_SIGNAL_H -# include <signal.h> -#endif #ifdef HAVE_UNISTD_H # include <unistd.h> #endif @@ -68,6 +66,7 @@ #ifdef ZEND_WIN32 # include <wincrypt.h> # include <process.h> +# include "win32/winutil.h" #endif #include <stdio.h> @@ -76,30 +75,17 @@ #include <sys/types.h> #include <sys/stat.h> -#if HAVE_LIMITS_H #include <limits.h> -#endif #include <fcntl.h> #include <errno.h> #ifndef _WIN32 -# ifdef HAVE_MREMAP -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -# ifndef __USE_GNU -# define __USE_GNU -# endif -# endif # 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 @@ -110,12 +96,21 @@ # define REAL_PAGE_SIZE _real_page_size static size_t _real_page_size = ZEND_MM_PAGE_SIZE; # endif +# ifdef MAP_ALIGNED_SUPER +# define MAP_HUGETLB MAP_ALIGNED_SUPER +# endif #endif #ifndef REAL_PAGE_SIZE # define REAL_PAGE_SIZE ZEND_MM_PAGE_SIZE #endif +/* NetBSD has an mremap() function with a signature that is incompatible with Linux (WTF?), + * so pretend it doesn't exist. */ +#ifndef __linux__ +# undef HAVE_MREMAP +#endif + #ifndef ZEND_MM_STAT # define ZEND_MM_STAT 1 /* track current and peak memory usage */ #endif @@ -194,10 +189,10 @@ typedef struct _zend_mm_huge_list zend_mm_huge_list; int zend_mm_use_huge_pages = 0; /* - * Memory is retrived from OS by chunks of fixed size 2MB. + * Memory is retrieved from OS by chunks of fixed size 2MB. * Inside chunk it's managed by pages of fixed size 4096B. * So each chunk consists from 512 pages. - * The first page of each chunk is reseved for chunk header. + * The first page of each chunk is reserved for chunk header. * It contains service information about all pages. * * free_pages - current number of free pages in this chunk @@ -252,7 +247,7 @@ struct _zend_mm_heap { zend_mm_chunk *main_chunk; zend_mm_chunk *cached_chunks; /* list of unused chunks */ - int chunks_count; /* number of alocated chunks */ + int chunks_count; /* number of allocated chunks */ int peak_chunks_count; /* peak number of allocated chunks for current request */ int cached_chunks_count; /* number of cached chunks */ double avg_chunks_count; /* average number of chunks allocated per request */ @@ -392,23 +387,17 @@ static ZEND_COLD ZEND_NORETURN void zend_mm_safe_error(zend_mm_heap *heap, void stderr_last_error(char *msg) { - LPSTR buf = NULL; DWORD err = GetLastError(); + char *buf = php_win32_error_to_msg(err); - if (!FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&buf, - 0, NULL)) { + if (!buf[0]) { fprintf(stderr, "\n%s: [0x%08lx]\n", msg, err); } else { fprintf(stderr, "\n%s: [0x%08lx] %s\n", msg, err, buf); } + + php_win32_error_msg_free(buf); } #endif @@ -416,6 +405,7 @@ stderr_last_error(char *msg) /* OS Allocation */ /*****************/ +#ifndef HAVE_MREMAP static void *zend_mm_mmap_fixed(void *addr, size_t size) { #ifdef _WIN32 @@ -444,6 +434,7 @@ static void *zend_mm_mmap_fixed(void *addr, size_t size) return ptr; #endif } +#endif static void *zend_mm_mmap(size_t size) { @@ -592,12 +583,12 @@ static zend_always_inline int zend_mm_bitset_is_set(zend_mm_bitset *bitset, int static zend_always_inline void zend_mm_bitset_set_bit(zend_mm_bitset *bitset, int bit) { - bitset[bit / ZEND_MM_BITSET_LEN] |= (Z_L(1) << (bit & (ZEND_MM_BITSET_LEN-1))); + bitset[bit / ZEND_MM_BITSET_LEN] |= (Z_UL(1) << (bit & (ZEND_MM_BITSET_LEN-1))); } static zend_always_inline void zend_mm_bitset_reset_bit(zend_mm_bitset *bitset, int bit) { - bitset[bit / ZEND_MM_BITSET_LEN] &= ~(Z_L(1) << (bit & (ZEND_MM_BITSET_LEN-1))); + bitset[bit / ZEND_MM_BITSET_LEN] &= ~(Z_UL(1) << (bit & (ZEND_MM_BITSET_LEN-1))); } static zend_always_inline void zend_mm_bitset_set_range(zend_mm_bitset *bitset, int start, int len) @@ -807,7 +798,16 @@ static int zend_mm_chunk_extend(zend_mm_heap *heap, void *addr, size_t old_size, } } #endif -#ifndef _WIN32 +#ifdef HAVE_MREMAP + /* We don't use MREMAP_MAYMOVE due to alignment requirements. */ + void *ptr = mremap(addr, old_size, new_size, 0); + if (ptr == MAP_FAILED) { + return 0; + } + /* Sanity check: The mapping shouldn't have moved. */ + ZEND_ASSERT(ptr == addr); + return 1; +#elif !defined(_WIN32) return (zend_mm_mmap_fixed((char*)addr + old_size, new_size - old_size) != NULL); #else return 0; @@ -1273,7 +1273,7 @@ static zend_never_inline void *zend_mm_alloc_small_slow(zend_mm_heap *heap, uint return (char*)bin; } -static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, size_t size, int bin_num ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, int bin_num ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { #if ZEND_MM_STAT do { @@ -1357,7 +1357,7 @@ static zend_always_inline void *zend_mm_alloc_heap(zend_mm_heap *heap, size_t si } #endif if (EXPECTED(size <= ZEND_MM_MAX_SMALL_SIZE)) { - ptr = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + ptr = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); #if ZEND_DEBUG dbg = zend_mm_get_debug_info(heap, ptr); dbg->size = real_size; @@ -1446,14 +1446,12 @@ static zend_never_inline void *zend_mm_realloc_slow(zend_mm_heap *heap, void *pt #if ZEND_MM_STAT do { size_t orig_peak = heap->peak; - size_t orig_real_peak = heap->real_peak; #endif ret = zend_mm_alloc_heap(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); memcpy(ret, ptr, copy_size); zend_mm_free_heap(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); #if ZEND_MM_STAT heap->peak = MAX(orig_peak, heap->size); - heap->real_peak = MAX(orig_real_peak, heap->real_size); } while (0); #endif return ret; @@ -1585,7 +1583,7 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p /* Check if truncation is necessary */ if (old_bin_num > 0 && size < bin_data_size[old_bin_num - 1]) { /* truncation */ - ret = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + ret = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); copy_size = use_copy_size ? MIN(size, copy_size) : size; memcpy(ret, ptr, copy_size); zend_mm_free_small(heap, ptr, old_bin_num); @@ -1599,15 +1597,13 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p #if ZEND_MM_STAT do { size_t orig_peak = heap->peak; - size_t orig_real_peak = heap->real_peak; #endif - ret = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + ret = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); copy_size = use_copy_size ? MIN(old_size, copy_size) : old_size; memcpy(ret, ptr, copy_size); zend_mm_free_small(heap, ptr, old_bin_num); #if ZEND_MM_STAT heap->peak = MAX(orig_peak, heap->size); - heap->real_peak = MAX(orig_real_peak, heap->real_size); } while (0); #endif } else { @@ -2012,7 +2008,7 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap) int pages_count = bin_pages[bin_num]; if (ZEND_MM_SRUN_FREE_COUNTER(info) == bin_elements[bin_num]) { - /* all elemens are free */ + /* all elements are free */ zend_mm_free_pages_ex(heap, chunk, i, pages_count, 0); collected += pages_count; } else { @@ -2284,8 +2280,6 @@ void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent) /* free the first chunk */ zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE); } else { - zend_mm_heap old_heap; - /* free some cached chunks to keep average count */ heap->avg_chunks_count = (heap->avg_chunks_count + (double)heap->peak_chunks_count) / 2.0; while ((double)heap->cached_chunks_count + 0.9 > heap->avg_chunks_count && @@ -2305,30 +2299,32 @@ void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent) } /* reinitialize the first chunk and heap */ - old_heap = *heap; p = heap->main_chunk; - memset(p, 0, ZEND_MM_FIRST_PAGE * ZEND_MM_PAGE_SIZE); - *heap = old_heap; - memset(heap->free_slot, 0, sizeof(heap->free_slot)); - heap->main_chunk = p; p->heap = &p->heap_slot; p->next = p; p->prev = p; p->free_pages = ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE; p->free_tail = ZEND_MM_FIRST_PAGE; - p->free_map[0] = (1L << ZEND_MM_FIRST_PAGE) - 1; - p->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE); - heap->chunks_count = 1; - heap->peak_chunks_count = 1; - heap->last_chunks_delete_boundary = 0; - heap->last_chunks_delete_count = 0; + p->num = 0; + +#if ZEND_MM_STAT + heap->size = heap->peak = 0; +#endif + memset(heap->free_slot, 0, sizeof(heap->free_slot)); #if ZEND_MM_STAT || ZEND_MM_LIMIT heap->real_size = ZEND_MM_CHUNK_SIZE; #endif #if ZEND_MM_STAT heap->real_peak = ZEND_MM_CHUNK_SIZE; - heap->size = heap->peak = 0; #endif + heap->chunks_count = 1; + heap->peak_chunks_count = 1; + heap->last_chunks_delete_boundary = 0; + heap->last_chunks_delete_count = 0; + + memset(p->free_map, 0, sizeof(p->free_map) + sizeof(p->map)); + p->free_map[0] = (1L << ZEND_MM_FIRST_PAGE) - 1; + p->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE); } } @@ -2371,7 +2367,8 @@ typedef struct _zend_alloc_globals { #ifdef ZTS static int alloc_globals_id; -# define AG(v) ZEND_TSRMG(alloc_globals_id, zend_alloc_globals *, v) +static size_t alloc_globals_offset; +# define AG(v) ZEND_TSRMG_FAST(alloc_globals_offset, zend_alloc_globals *, v) #else # define AG(v) (alloc_globals.v) static zend_alloc_globals alloc_globals; @@ -2386,6 +2383,40 @@ ZEND_API int is_zend_mm(void) #endif } +ZEND_API int is_zend_ptr(const void *ptr) +{ +#if ZEND_MM_CUSTOM + if (AG(mm_heap)->use_custom_heap) { + return 0; + } +#endif + + if (AG(mm_heap)->main_chunk) { + zend_mm_chunk *chunk = AG(mm_heap)->main_chunk; + + do { + if (ptr >= (void*)chunk + && ptr < (void*)((char*)chunk + ZEND_MM_CHUNK_SIZE)) { + return 1; + } + chunk = chunk->next; + } while (chunk != AG(mm_heap)->main_chunk); + } + + if (AG(mm_heap)->huge_list) { + zend_mm_huge_list *block = AG(mm_heap)->huge_list; + + do { + if (ptr >= (void*)block + && ptr < (void*)((char*)block + block->size)) { + return 1; + } + block = block->next; + } while (block != AG(mm_heap)->huge_list); + } + return 0; +} + #if !ZEND_DEBUG && defined(HAVE_BUILTIN_CONSTANT_P) #undef _emalloc @@ -2417,7 +2448,7 @@ ZEND_API int is_zend_mm(void) # define _ZEND_BIN_ALLOCATOR(_num, _size, _elements, _pages, x, y) \ ZEND_API void* ZEND_FASTCALL _emalloc_ ## _size(void) { \ ZEND_MM_CUSTOM_ALLOCATOR(_size); \ - return zend_mm_alloc_small(AG(mm_heap), _size, _num ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); \ + return zend_mm_alloc_small(AG(mm_heap), _num ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); \ } ZEND_MM_BINS_INFO(_ZEND_BIN_ALLOCATOR, x, y) @@ -2555,7 +2586,7 @@ ZEND_API size_t ZEND_FASTCALL _zend_mem_block_size(void *ptr ZEND_FILE_LINE_DC Z ZEND_API void* ZEND_FASTCALL _safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { - return emalloc_rel(zend_safe_address_guarded(nmemb, size, offset)); + return _emalloc(zend_safe_address_guarded(nmemb, size, offset) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); } ZEND_API void* ZEND_FASTCALL _safe_malloc(size_t nmemb, size_t size, size_t offset) @@ -2565,7 +2596,7 @@ ZEND_API void* ZEND_FASTCALL _safe_malloc(size_t nmemb, size_t size, size_t offs ZEND_API void* ZEND_FASTCALL _safe_erealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { - return erealloc_rel(ptr, zend_safe_address_guarded(nmemb, size, offset)); + return _erealloc(ptr, zend_safe_address_guarded(nmemb, size, offset) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); } ZEND_API void* ZEND_FASTCALL _safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset) @@ -2578,7 +2609,7 @@ ZEND_API void* ZEND_FASTCALL _ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_D void *p; size = zend_safe_address_guarded(nmemb, size, 0); - p = emalloc_rel(size); + p = _emalloc(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); memset(p, 0, size); return p; } @@ -2689,7 +2720,6 @@ static void alloc_globals_ctor(zend_alloc_globals *alloc_globals) if (tmp && zend_atoi(tmp, 0)) { zend_mm_use_huge_pages = 1; } - ZEND_TSRMLS_CACHE_UPDATE(); alloc_globals->mm_heap = zend_mm_init(); } @@ -2703,7 +2733,7 @@ static void alloc_globals_dtor(zend_alloc_globals *alloc_globals) ZEND_API void start_memory_manager(void) { #ifdef ZTS - ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + ts_allocate_fast_id(&alloc_globals_id, &alloc_globals_offset, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); #else alloc_globals_ctor(&alloc_globals); #endif @@ -2926,12 +2956,9 @@ ZEND_API void * __zend_realloc(void *p, size_t len) zend_out_of_memory(); } -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - * vim600: sw=4 ts=4 fdm=marker - * vim<600: sw=4 ts=4 - */ +#ifdef ZTS +size_t zend_mm_globals_size(void) +{ + return sizeof(zend_alloc_globals); +} +#endif |