cvs: ZendEngine2(PHP_5_2) / zend_alloc.c php-src NEWS

From: Date: Fri, 15 Dec 2006 13:25:26 +0000
Subject: cvs: ZendEngine2(PHP_5_2) / zend_alloc.c php-src NEWS
Groups: php.zend-engine.cvs 
Request: Send a blank email to php-zend-engine-cvs+get-5465@lists.php.net to get a copy of this message
dmitry Fri Dec 15 13:25:26 2006 UTC Modified files: (Branch: PHP_5_2) /php-src NEWS /ZendEngine2 zend_alloc.c Log: Added internal heap protection . safe unlinking . cookies . canary protection (debug build only)

http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.430&r2=1.2027.2.547.2.431&diff_format=u Index: php-src/NEWS diff -u php-src/NEWS:1.2027.2.547.2.430 php-src/NEWS:1.2027.2.547.2.431 --- php-src/NEWS:1.2027.2.547.2.430 Fri Dec 15 01:21:36 2006 +++ php-src/NEWS Fri Dec 15 13:25:26 2006 @@ -1,6 +1,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 14 Dec 2006, PHP 5.2.1RC1 +- Added internal heap protection (Dmitry) + . safe unlinking + . cookies + . canary protection (debug build only) - Added a meta tag to phpinfo() output to prevent search engines from indexing the page. (Ilia) - Added new function, sys_get_temp_dir(). (Hartmut) http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_alloc.c?r1=1.144.2.3.2.22&r2=1.144.2.3.2.23&diff_format=u Index: ZendEngine2/zend_alloc.c diff -u ZendEngine2/zend_alloc.c:1.144.2.3.2.22 ZendEngine2/zend_alloc.c:1.144.2.3.2.23 --- ZendEngine2/zend_alloc.c:1.144.2.3.2.22 Fri Dec 8 12:47:45 2006 +++ ZendEngine2/zend_alloc.c Fri Dec 15 13:25:26 2006 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_alloc.c,v 1.144.2.3.2.22 2006/12/08 12:47:45 dmitry Exp $ */ +/* $Id: zend_alloc.c,v 1.144.2.3.2.23 2006/12/15 13:25:26 dmitry Exp $ */ #include "zend.h" #include "zend_alloc.h" @@ -36,6 +36,18 @@ # 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, ...) { @@ -54,6 +66,15 @@ } #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); @@ -189,7 +210,7 @@ { HANDLE heap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0); zend_mm_storage* storage; - + if (heap == NULL) { return NULL; } @@ -281,24 +302,43 @@ 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; @@ -306,6 +346,9 @@ 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; @@ -340,6 +383,24 @@ 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 @@ -353,6 +414,7 @@ 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; \ @@ -413,8 +475,11 @@ #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 @@ -427,38 +492,91 @@ # 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; @@ -497,6 +615,13 @@ 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; @@ -614,6 +739,41 @@ 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); @@ -792,7 +952,6 @@ int no_cache_notice = 0; int had_problems = 0; int valid_beginning = 1; - long *end_magic; if (silent==2) { silent = 1; @@ -928,43 +1087,80 @@ } } - 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"); @@ -1134,16 +1330,8 @@ 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 @@ -1193,6 +1381,8 @@ #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); { @@ -1297,18 +1487,7 @@ } } -#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; @@ -1334,8 +1513,9 @@ } 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 @@ -1431,7 +1611,8 @@ 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; @@ -1458,20 +1639,15 @@ #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; @@ -1493,14 +1669,7 @@ /* 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) { @@ -1607,18 +1776,7 @@ 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) { @@ -1630,7 +1788,7 @@ } 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); @@ -1662,7 +1820,8 @@ 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);
« previous php.zend-engine.cvs (#5465) next »