# define ZEND_USE_MALLOC_MM ZEND_DEBUG
#endif
+#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
+# define ZEND_MM_COOKIES 1
+#endif
+
#if ZEND_DEBUG
void zend_debug_alloc_output(char *format, ...)
{
}
#endif
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
+# define EXPECTED(condition) __builtin_expect(condition, 1)
+# define UNEXPECTED(condition) __builtin_expect(condition, 0)
+static void zend_mm_panic(const char *message) __attribute__ ((noreturn));
+#else
+# define EXPECTED(condition) (condition)
+# define UNEXPECTED(condition) (condition)
+#endif
+
static void zend_mm_panic(const char *message)
{
fprintf(stderr, "%s\n", message);
{
HANDLE heap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
zend_mm_storage* storage;
-
+
if (heap == NULL) {
return NULL;
}
typedef struct _zend_mm_block_info {
size_t _size;
size_t _prev;
+#if ZEND_MM_COOKIES
+ unsigned long _cookie;
+#endif
} zend_mm_block_info;
+#if ZEND_DEBUG
+
typedef struct _zend_mm_debug_info {
char *filename;
uint lineno;
char *orig_filename;
uint orig_lineno;
size_t size;
+#if ZEND_MM_HEAP_PROTECTION
+ unsigned int start_magic;
+#endif
} zend_mm_debug_info;
+#elif ZEND_MM_HEAP_PROTECTION
+
+typedef struct _zend_mm_debug_info {
+ size_t size;
+ unsigned int start_magic;
+} zend_mm_debug_info;
+
+#endif
+
typedef struct _zend_mm_block {
zend_mm_block_info info;
#if ZEND_DEBUG
mem_magic magic;
- zend_mm_debug_info debug;
# ifdef ZTS
THREAD_T thread_id;
# endif
+ zend_mm_debug_info debug;
+#elif ZEND_MM_HEAP_PROTECTION
+ zend_mm_debug_info debug;
#endif
} zend_mm_block;
zend_mm_block_info info;
#if ZEND_DEBUG
mem_magic 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_free_block free_buckets[ZEND_MM_NUM_BUCKETS];
};
+
+#if ZEND_MM_COOKIES
+
+static unsigned int _zend_mm_cookie = 0;
+
+# define ZEND_MM_COOKIE(block) \
+ (((unsigned long)(block)) ^ _zend_mm_cookie)
+# 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
+
/* Reserved space for error reporting in case of memory overflow */
#define ZEND_MM_RESERVE_SIZE 8*1024
size_t _size = (size); \
(b)->info._size = (type) | _size; \
ZEND_MM_BLOCK_AT(b, _size)->info._prev = (type) | _size; \
+ ZEND_MM_SET_COOKIE(b); \
} while (0);
#define ZEND_MM_LAST_BLOCK(b) do { \
(b)->info._size = ZEND_MM_GUARD_BLOCK | ZEND_MM_ALIGNED_HEADER_SIZE; \
#if ZEND_DEBUG
# ifdef ZTS
+# define ZEND_MM_SET_THREAD_ID(block) \
+ ((zend_mm_block*)(block))->thread_id = tsrm_thread_id()
# define ZEND_MM_BAD_THREAD_ID(block) ((block)->thread_id != tsrm_thread_id())
# else
+# define ZEND_MM_SET_THREAD_ID(block)
# define ZEND_MM_BAD_THREAD_ID(block) 0
# endif
# define ZEND_MM_CHECK_MAGIC(block, val) do { \
if ((block)->magic != (val)) { \
- zend_mm_panic("Heap corrupted"); \
+ zend_mm_panic("zend_mm_heap corrupted"); \
} \
} while (0)
-# define ZEND_MM_END_MAGIC_PTR(block) \
- (long*)(((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->debug.size)
-
-# define ZEND_MM_SET_END_MAGIC(block) do { \
- long *p = ZEND_MM_END_MAGIC_PTR(block); \
- memcpy(p, &_mem_block_end_magic, END_MAGIC_SIZE); \
+# 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); \
+ } \
} while (0)
-# define MEM_BLOCK_END_MAGIC 0x2A8FCC84L
-
-# define END_MAGIC_SIZE sizeof(long)
-
-static long _mem_block_end_magic = MEM_BLOCK_END_MAGIC;
-
#else
# define ZEND_MM_VALID_PTR(ptr) (ptr != NULL)
# define ZEND_MM_SET_MAGIC(block, val)
-# define ZEND_MM_SET_END_MAGIC(block)
-
# define ZEND_MM_CHECK_MAGIC(block, val)
+# 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) \
+ (unsigned int*)(((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->debug.size)
+
+# define END_MAGIC_SIZE sizeof(unsigned int)
+
+# define ZEND_MM_SET_BLOCK_SIZE(block, __size) do { \
+ unsigned int *p; \
+ ((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)
+
# define END_MAGIC_SIZE 0
#endif
+#if ZEND_MM_SAFE_UNLINKING
+# define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \
+ if (UNEXPECTED((block)->info._size != ZEND_MM_NEXT_BLOCK(block)->info._prev) || \
+ 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"); \
+ }
+#else
+# define ZEND_MM_CHECK_BLOCK_LINKAGE(block)
+#endif
+
+
+
static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
{
zend_mm_free_block *prev, *next;
prev = mm_block->prev_free_block;
next = mm_block->next_free_block;
+
+#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;
exit(0);
#endif
+#if ZEND_MM_HEAP_PROTECTION
+ if (_mem_block_start_magic == 0) {
+ int r;
+ do {
+ r = rand();
+ } while (!(r&0xff000000) ||
+ !(r&0x00ff0000) ||
+ !(r&0x0000ff00) ||
+ !(r&0x000000ff));
+ _mem_block_start_magic = r;
+ }
+ if (_mem_block_end_magic == 0) {
+ int r;
+ do {
+ r = rand();
+ } while (!(r&0xff000000) ||
+ !(r&0x00ff0000) ||
+ !(r&0x0000ff00) ||
+ !(r&0x000000ff));
+ _mem_block_end_magic = r;
+ }
+#endif
+#if ZEND_MM_COOKIES
+ if (_zend_mm_cookie == 0) {
+ int r;
+ do {
+ r = rand();
+ } while (!(r&0xff000000) ||
+ !(r&0x00ff0000) ||
+ !(r&0x0000ff00) ||
+ !(r&0x000000ff));
+ _zend_mm_cookie = r;
+ }
+#endif
+
storage = handlers->init(params);
if (!storage) {
fprintf(stderr, "Cannot initialize zend_mm storage [%s]\n", handlers->name);
int no_cache_notice = 0;
int had_problems = 0;
int valid_beginning = 1;
- long *end_magic;
if (silent==2) {
silent = 1;
}
}
- end_magic = ZEND_MM_END_MAGIC_PTR(p);
+#if ZEND_MM_HEAP_PROTECTION
if (!valid_beginning) {
if (!silent) {
- zend_debug_alloc_output("%10s\t", "End:");
+ zend_debug_alloc_output("%10s\t", "Start:");
zend_debug_alloc_output("Unknown\n");
- }
- } else 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");
+ zend_debug_alloc_output("Unknown\n");
}
} else {
- char *overflow_ptr, *magic_ptr=(char *) &_mem_block_end_magic;
- int overflows=0;
- long i;
+ unsigned int *end_magic = ZEND_MM_END_MAGIC_PTR(p);
- 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;
+ 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;
- for (i=0; i<(int)sizeof(long); i++) {
- if (overflow_ptr[i]!=magic_ptr[i]) {
- overflows++;
+ 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);
}
}
-
- zend_debug_alloc_output("%10s\t", "End:");
- zend_debug_alloc_output("Overflown (magic=0x%0.8lX instead of 0x%0.8lX)\n", *end_magic, MEM_BLOCK_END_MAGIC);
- zend_debug_alloc_output("%10s\t","");
- if (overflows>=(int)sizeof(long)) {
- zend_debug_alloc_output("At least %d bytes overflown\n", sizeof(long));
+ 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");
+ }
} else {
- zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
+ 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);
+ }
}
}
+#endif
if (!silent) {
zend_debug_alloc_output("---------------------------------------\n");
best_fit = heap->cache[index];
heap->cache[index] = best_fit->prev_free_block;
heap->cached -= true_size;
-#if ZEND_DEBUG
ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
- ZEND_MM_SET_MAGIC(best_fit, MEM_BLOCK_VALID);
- ((zend_mm_block*)best_fit)->debug.size = size;
- ((zend_mm_block*)best_fit)->debug.filename = __zend_filename;
- ((zend_mm_block*)best_fit)->debug.lineno = __zend_lineno;
- ((zend_mm_block*)best_fit)->debug.orig_filename = __zend_orig_filename;
- ((zend_mm_block*)best_fit)->debug.orig_lineno = __zend_orig_lineno;
- ZEND_MM_SET_END_MAGIC(best_fit);
-#endif
+ ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
return ZEND_MM_DATA_OF(best_fit);
}
#endif
#if ZEND_DEBUG
ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED);
#endif
+ ZEND_MM_CHECK_COOKIE(best_fit);
+ ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit);
zend_mm_remove_from_free_list(heap, best_fit);
{
}
}
-#if ZEND_DEBUG
- ZEND_MM_SET_MAGIC(best_fit, MEM_BLOCK_VALID);
- ((zend_mm_block*)best_fit)->debug.size = size;
- ((zend_mm_block*)best_fit)->debug.filename = __zend_filename;
- ((zend_mm_block*)best_fit)->debug.lineno = __zend_lineno;
- ((zend_mm_block*)best_fit)->debug.orig_filename = __zend_orig_filename;
- ((zend_mm_block*)best_fit)->debug.orig_lineno = __zend_orig_lineno;
-# ifdef ZTS
- ((zend_mm_block*)best_fit)->thread_id = tsrm_thread_id();
-# endif
- ZEND_MM_SET_END_MAGIC(best_fit);
-#endif
+ ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1);
#if MEMORY_LIMIT
heap->size += true_size;
}
mm_block = ZEND_MM_HEADER_OF(p);
size = ZEND_MM_BLOCK_SIZE(mm_block);
+ ZEND_MM_CHECK_PROTECTION(mm_block);
-#if ZEND_DEBUG
+#if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
memset(ZEND_MM_DATA_OF(mm_block), 0x5a, mm_block->debug.size);
#endif
mm_block = ZEND_MM_HEADER_OF(p);
true_size = ZEND_MM_TRUE_SIZE(size);
orig_size = ZEND_MM_BLOCK_SIZE(mm_block);
-
+ ZEND_MM_CHECK_PROTECTION(mm_block);
+
if (true_size <= orig_size) {
size_t remaining_size = orig_size - true_size;
#endif
HANDLE_UNBLOCK_INTERRUPTIONS();
}
-#if ZEND_DEBUG
- mm_block->debug.size = size;
- mm_block->debug.filename = __zend_filename;
- mm_block->debug.lineno = __zend_lineno;
- mm_block->debug.orig_filename = __zend_orig_filename;
- mm_block->debug.orig_lineno = __zend_orig_lineno;
- ZEND_MM_SET_END_MAGIC(mm_block);
-#endif
+ ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
return p;
}
next_block = ZEND_MM_NEXT_BLOCK(mm_block);
if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
+ ZEND_MM_CHECK_COOKIE(next_block);
+ ZEND_MM_CHECK_BLOCK_LINKAGE(next_block);
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);
size_t remaining_size = block_size - true_size;
/* add the new free block to the free list */
zend_mm_add_to_free_list(heap, new_free_block);
}
-#if ZEND_DEBUG
- mm_block->debug.size = size;
- mm_block->debug.filename = __zend_filename;
- mm_block->debug.lineno = __zend_lineno;
- mm_block->debug.orig_filename = __zend_orig_filename;
- mm_block->debug.orig_lineno = __zend_orig_lineno;
- ZEND_MM_SET_END_MAGIC(mm_block);
-#endif
+ ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
#if MEMORY_LIMIT
heap->size = heap->size + true_size - orig_size;
if (heap->peak < heap->size) {
zend_mm_add_to_free_list(heap, new_free_block);
}
-#if ZEND_DEBUG
- ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_VALID);
- mm_block->debug.size = size;
- mm_block->debug.filename = __zend_filename;
- mm_block->debug.lineno = __zend_lineno;
- mm_block->debug.orig_filename = __zend_orig_filename;
- mm_block->debug.orig_lineno = __zend_orig_lineno;
-# ifdef ZTS
- mm_block->thread_id = tsrm_thread_id();
-# endif
- ZEND_MM_SET_END_MAGIC(mm_block);
-#endif
+ ZEND_MM_SET_DEBUG_INFO(mm_block, size, 1, 1);
#if MEMORY_LIMIT
heap->size = heap->size + true_size - orig_size;
if (heap->peak < heap->size) {
}
ptr = _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
-#if ZEND_DEBUG
+#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);
return 0;
}
mm_block = ZEND_MM_HEADER_OF(p);
-#if ZEND_DEBUG
+ ZEND_MM_CHECK_PROTECTION(mm_block);
+#if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
return mm_block->debug.size;
#else
return ZEND_MM_BLOCK_SIZE(mm_block);