summaryrefslogtreecommitdiff
path: root/Zend/zend_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_alloc.c')
-rw-r--r--Zend/zend_alloc.c171
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