You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2815 lines
78 KiB

27 years ago
12 years ago
27 years ago
24 years ago
24 years ago
27 years ago
27 years ago
19 years ago
27 years ago
27 years ago
27 years ago
19 years ago
27 years ago
17 years ago
17 years ago
17 years ago
15 years ago
17 years ago
17 years ago
17 years ago
27 years ago
27 years ago
27 years ago
27 years ago
17 years ago
17 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
22 years ago
27 years ago
22 years ago
27 years ago
15 years ago
19 years ago
20 years ago
19 years ago
19 years ago
14 years ago
19 years ago
19 years ago
19 years ago
19 years ago
14 years ago
19 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
23 years ago
23 years ago
19 years ago
23 years ago
23 years ago
23 years ago
19 years ago
23 years ago
23 years ago
23 years ago
23 years ago
19 years ago
19 years ago
19 years ago
24 years ago
14 years ago
24 years ago
24 years ago
27 years ago
14 years ago
27 years ago
27 years ago
27 years ago
27 years ago
14 years ago
27 years ago
27 years ago
27 years ago
14 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2014 Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Andi Gutmans <andi@zend.com> |
  16. | Zeev Suraski <zeev@zend.com> |
  17. | Dmitry Stogov <dmitry@zend.com> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id$ */
  21. #include "zend.h"
  22. #include "zend_alloc.h"
  23. #include "zend_globals.h"
  24. #include "zend_operators.h"
  25. #ifdef HAVE_SIGNAL_H
  26. # include <signal.h>
  27. #endif
  28. #ifdef HAVE_UNISTD_H
  29. # include <unistd.h>
  30. #endif
  31. #ifdef ZEND_WIN32
  32. # include <wincrypt.h>
  33. # include <process.h>
  34. #endif
  35. #ifndef ZEND_MM_HEAP_PROTECTION
  36. # define ZEND_MM_HEAP_PROTECTION ZEND_DEBUG
  37. #endif
  38. #ifndef ZEND_MM_SAFE_UNLINKING
  39. # define ZEND_MM_SAFE_UNLINKING 1
  40. #endif
  41. #ifndef ZEND_MM_COOKIES
  42. # define ZEND_MM_COOKIES ZEND_DEBUG
  43. #endif
  44. #ifdef _WIN64
  45. # define PTR_FMT "0x%0.16I64x"
  46. /*
  47. #elif sizeof(long) == 8
  48. # define PTR_FMT "0x%0.16lx"
  49. */
  50. #else
  51. # define PTR_FMT "0x%0.8lx"
  52. #endif
  53. #if ZEND_DEBUG
  54. void zend_debug_alloc_output(char *format, ...)
  55. {
  56. char output_buf[256];
  57. va_list args;
  58. va_start(args, format);
  59. vsprintf(output_buf, format, args);
  60. va_end(args);
  61. #ifdef ZEND_WIN32
  62. OutputDebugString(output_buf);
  63. #else
  64. fprintf(stderr, "%s", output_buf);
  65. #endif
  66. }
  67. #endif
  68. #if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
  69. static void zend_mm_panic(const char *message) __attribute__ ((noreturn));
  70. #endif
  71. static void zend_mm_panic(const char *message)
  72. {
  73. fprintf(stderr, "%s\n", message);
  74. /* See http://support.microsoft.com/kb/190351 */
  75. #ifdef PHP_WIN32
  76. fflush(stderr);
  77. #endif
  78. #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID)
  79. kill(getpid(), SIGSEGV);
  80. #endif
  81. exit(1);
  82. }
  83. /*******************/
  84. /* Storage Manager */
  85. /*******************/
  86. #ifdef ZEND_WIN32
  87. # define HAVE_MEM_WIN32 /* use VirtualAlloc() to allocate memory */
  88. #endif
  89. #define HAVE_MEM_MALLOC /* use malloc() to allocate segments */
  90. #include <sys/types.h>
  91. #include <sys/stat.h>
  92. #if HAVE_LIMITS_H
  93. #include <limits.h>
  94. #endif
  95. #include <fcntl.h>
  96. #include <errno.h>
  97. #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
  98. # ifdef HAVE_MREMAP
  99. # ifndef _GNU_SOURCE
  100. # define _GNU_SOURCE
  101. # endif
  102. # ifndef __USE_GNU
  103. # define __USE_GNU
  104. # endif
  105. # endif
  106. # include <sys/mman.h>
  107. # ifndef MAP_ANON
  108. # ifdef MAP_ANONYMOUS
  109. # define MAP_ANON MAP_ANONYMOUS
  110. # endif
  111. # endif
  112. # ifndef MREMAP_MAYMOVE
  113. # define MREMAP_MAYMOVE 0
  114. # endif
  115. # ifndef MAP_FAILED
  116. # define MAP_FAILED ((void*)-1)
  117. # endif
  118. #endif
  119. static zend_mm_storage* zend_mm_mem_dummy_init(void *params)
  120. {
  121. return malloc(sizeof(zend_mm_storage));
  122. }
  123. static void zend_mm_mem_dummy_dtor(zend_mm_storage *storage)
  124. {
  125. free(storage);
  126. }
  127. static void zend_mm_mem_dummy_compact(zend_mm_storage *storage)
  128. {
  129. }
  130. #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
  131. static zend_mm_segment* zend_mm_mem_mmap_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
  132. {
  133. zend_mm_segment *ret;
  134. #ifdef HAVE_MREMAP
  135. #if defined(__NetBSD__)
  136. /* NetBSD 5 supports mremap but takes an extra newp argument */
  137. ret = (zend_mm_segment*)mremap(segment, segment->size, segment, size, MREMAP_MAYMOVE);
  138. #else
  139. ret = (zend_mm_segment*)mremap(segment, segment->size, size, MREMAP_MAYMOVE);
  140. #endif
  141. if (ret == MAP_FAILED) {
  142. #endif
  143. ret = storage->handlers->_alloc(storage, size);
  144. if (ret) {
  145. memcpy(ret, segment, size > segment->size ? segment->size : size);
  146. storage->handlers->_free(storage, segment);
  147. }
  148. #ifdef HAVE_MREMAP
  149. }
  150. #endif
  151. return ret;
  152. }
  153. static void zend_mm_mem_mmap_free(zend_mm_storage *storage, zend_mm_segment* segment)
  154. {
  155. munmap((void*)segment, segment->size);
  156. }
  157. #endif
  158. #ifdef HAVE_MEM_MMAP_ANON
  159. static zend_mm_segment* zend_mm_mem_mmap_anon_alloc(zend_mm_storage *storage, size_t size)
  160. {
  161. zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
  162. if (ret == MAP_FAILED) {
  163. ret = NULL;
  164. }
  165. return ret;
  166. }
  167. # 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}
  168. #endif
  169. #ifdef HAVE_MEM_MMAP_ZERO
  170. static int zend_mm_dev_zero_fd = -1;
  171. static zend_mm_storage* zend_mm_mem_mmap_zero_init(void *params)
  172. {
  173. if (zend_mm_dev_zero_fd == -1) {
  174. zend_mm_dev_zero_fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
  175. }
  176. if (zend_mm_dev_zero_fd >= 0) {
  177. return malloc(sizeof(zend_mm_storage));
  178. } else {
  179. return NULL;
  180. }
  181. }
  182. static void zend_mm_mem_mmap_zero_dtor(zend_mm_storage *storage)
  183. {
  184. close(zend_mm_dev_zero_fd);
  185. free(storage);
  186. }
  187. static zend_mm_segment* zend_mm_mem_mmap_zero_alloc(zend_mm_storage *storage, size_t size)
  188. {
  189. zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zend_mm_dev_zero_fd, 0);
  190. if (ret == MAP_FAILED) {
  191. ret = NULL;
  192. }
  193. return ret;
  194. }
  195. # 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}
  196. #endif
  197. #ifdef HAVE_MEM_WIN32
  198. static zend_mm_storage* zend_mm_mem_win32_init(void *params)
  199. {
  200. HANDLE heap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
  201. zend_mm_storage* storage;
  202. if (heap == NULL) {
  203. return NULL;
  204. }
  205. storage = (zend_mm_storage*)malloc(sizeof(zend_mm_storage));
  206. if (storage == NULL) {
  207. HeapDestroy(heap);
  208. return NULL;
  209. }
  210. storage->data = (void*) heap;
  211. return storage;
  212. }
  213. static void zend_mm_mem_win32_dtor(zend_mm_storage *storage)
  214. {
  215. HeapDestroy((HANDLE)storage->data);
  216. free(storage);
  217. }
  218. static void zend_mm_mem_win32_compact(zend_mm_storage *storage)
  219. {
  220. HeapDestroy((HANDLE)storage->data);
  221. storage->data = (void*)HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
  222. }
  223. static zend_mm_segment* zend_mm_mem_win32_alloc(zend_mm_storage *storage, size_t size)
  224. {
  225. return (zend_mm_segment*) HeapAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, size);
  226. }
  227. static void zend_mm_mem_win32_free(zend_mm_storage *storage, zend_mm_segment* segment)
  228. {
  229. HeapFree((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment);
  230. }
  231. static zend_mm_segment* zend_mm_mem_win32_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
  232. {
  233. return (zend_mm_segment*) HeapReAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment, size);
  234. }
  235. # 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}
  236. #endif
  237. #ifdef HAVE_MEM_MALLOC
  238. static zend_mm_segment* zend_mm_mem_malloc_alloc(zend_mm_storage *storage, size_t size)
  239. {
  240. return (zend_mm_segment*)malloc(size);
  241. }
  242. static zend_mm_segment* zend_mm_mem_malloc_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size)
  243. {
  244. return (zend_mm_segment*)realloc(ptr, size);
  245. }
  246. static void zend_mm_mem_malloc_free(zend_mm_storage *storage, zend_mm_segment *ptr)
  247. {
  248. free(ptr);
  249. }
  250. # 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}
  251. #endif
  252. static const zend_mm_mem_handlers mem_handlers[] = {
  253. #ifdef HAVE_MEM_WIN32
  254. ZEND_MM_MEM_WIN32_DSC,
  255. #endif
  256. #ifdef HAVE_MEM_MALLOC
  257. ZEND_MM_MEM_MALLOC_DSC,
  258. #endif
  259. #ifdef HAVE_MEM_MMAP_ANON
  260. ZEND_MM_MEM_MMAP_ANON_DSC,
  261. #endif
  262. #ifdef HAVE_MEM_MMAP_ZERO
  263. ZEND_MM_MEM_MMAP_ZERO_DSC,
  264. #endif
  265. {NULL, NULL, NULL, NULL, NULL, NULL}
  266. };
  267. # define ZEND_MM_STORAGE_DTOR() heap->storage->handlers->dtor(heap->storage)
  268. # define ZEND_MM_STORAGE_ALLOC(size) heap->storage->handlers->_alloc(heap->storage, size)
  269. # define ZEND_MM_STORAGE_REALLOC(ptr, size) heap->storage->handlers->_realloc(heap->storage, ptr, size)
  270. # define ZEND_MM_STORAGE_FREE(ptr) heap->storage->handlers->_free(heap->storage, ptr)
  271. /****************/
  272. /* Heap Manager */
  273. /****************/
  274. #define MEM_BLOCK_VALID 0x7312F8DC
  275. #define MEM_BLOCK_FREED 0x99954317
  276. #define MEM_BLOCK_CACHED 0xFB8277DC
  277. #define MEM_BLOCK_GUARD 0x2A8FCC84
  278. #define MEM_BLOCK_LEAK 0x6C5E8F2D
  279. /* mm block type */
  280. typedef struct _zend_mm_block_info {
  281. #if ZEND_MM_COOKIES
  282. size_t _cookie;
  283. #endif
  284. size_t _size;
  285. size_t _prev;
  286. } zend_mm_block_info;
  287. #if ZEND_DEBUG
  288. typedef struct _zend_mm_debug_info {
  289. const char *filename;
  290. uint lineno;
  291. const char *orig_filename;
  292. uint orig_lineno;
  293. size_t size;
  294. #if ZEND_MM_HEAP_PROTECTION
  295. unsigned int start_magic;
  296. #endif
  297. } zend_mm_debug_info;
  298. #elif ZEND_MM_HEAP_PROTECTION
  299. typedef struct _zend_mm_debug_info {
  300. size_t size;
  301. unsigned int start_magic;
  302. } zend_mm_debug_info;
  303. #endif
  304. typedef struct _zend_mm_block {
  305. zend_mm_block_info info;
  306. #if ZEND_DEBUG
  307. unsigned int magic;
  308. # ifdef ZTS
  309. THREAD_T thread_id;
  310. # endif
  311. zend_mm_debug_info debug;
  312. #elif ZEND_MM_HEAP_PROTECTION
  313. zend_mm_debug_info debug;
  314. #endif
  315. } zend_mm_block;
  316. typedef struct _zend_mm_small_free_block {
  317. zend_mm_block_info info;
  318. #if ZEND_DEBUG
  319. unsigned int magic;
  320. # ifdef ZTS
  321. THREAD_T thread_id;
  322. # endif
  323. #endif
  324. struct _zend_mm_free_block *prev_free_block;
  325. struct _zend_mm_free_block *next_free_block;
  326. } zend_mm_small_free_block;
  327. typedef struct _zend_mm_free_block {
  328. zend_mm_block_info info;
  329. #if ZEND_DEBUG
  330. unsigned int magic;
  331. # ifdef ZTS
  332. THREAD_T thread_id;
  333. # endif
  334. #endif
  335. struct _zend_mm_free_block *prev_free_block;
  336. struct _zend_mm_free_block *next_free_block;
  337. struct _zend_mm_free_block **parent;
  338. struct _zend_mm_free_block *child[2];
  339. } zend_mm_free_block;
  340. #define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
  341. #define ZEND_MM_CACHE 1
  342. #define ZEND_MM_CACHE_SIZE (ZEND_MM_NUM_BUCKETS * 4 * 1024)
  343. #ifndef ZEND_MM_CACHE_STAT
  344. # define ZEND_MM_CACHE_STAT 0
  345. #endif
  346. struct _zend_mm_heap {
  347. int use_zend_alloc;
  348. void *(*_malloc)(size_t);
  349. void (*_free)(void*);
  350. void *(*_realloc)(void*, size_t);
  351. size_t free_bitmap;
  352. size_t large_free_bitmap;
  353. size_t block_size;
  354. size_t compact_size;
  355. zend_mm_segment *segments_list;
  356. zend_mm_storage *storage;
  357. size_t real_size;
  358. size_t real_peak;
  359. size_t limit;
  360. size_t size;
  361. size_t peak;
  362. size_t reserve_size;
  363. void *reserve;
  364. int overflow;
  365. int internal;
  366. #if ZEND_MM_CACHE
  367. unsigned int cached;
  368. zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
  369. #endif
  370. zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
  371. zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
  372. zend_mm_free_block *rest_buckets[2];
  373. int rest_count;
  374. #if ZEND_MM_CACHE_STAT
  375. struct {
  376. int count;
  377. int max_count;
  378. int hit;
  379. int miss;
  380. } cache_stat[ZEND_MM_NUM_BUCKETS+1];
  381. #endif
  382. };
  383. #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
  384. (zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \
  385. sizeof(zend_mm_free_block*) * 2 - \
  386. sizeof(zend_mm_small_free_block))
  387. #define ZEND_MM_REST_BUCKET(heap) \
  388. (zend_mm_free_block*)((char*)&heap->rest_buckets[0] + \
  389. sizeof(zend_mm_free_block*) * 2 - \
  390. sizeof(zend_mm_small_free_block))
  391. #define ZEND_MM_REST_BLOCK ((zend_mm_free_block**)(zend_uintptr_t)(1))
  392. #define ZEND_MM_MAX_REST_BLOCKS 16
  393. #if ZEND_MM_COOKIES
  394. static unsigned int _zend_mm_cookie = 0;
  395. # define ZEND_MM_COOKIE(block) \
  396. (((size_t)(block)) ^ _zend_mm_cookie)
  397. # define ZEND_MM_SET_COOKIE(block) \
  398. (block)->info._cookie = ZEND_MM_COOKIE(block)
  399. # define ZEND_MM_CHECK_COOKIE(block) \
  400. if (UNEXPECTED((block)->info._cookie != ZEND_MM_COOKIE(block))) { \
  401. zend_mm_panic("zend_mm_heap corrupted"); \
  402. }
  403. #else
  404. # define ZEND_MM_SET_COOKIE(block)
  405. # define ZEND_MM_CHECK_COOKIE(block)
  406. #endif
  407. /* Default memory segment size */
  408. #define ZEND_MM_SEG_SIZE (256 * 1024)
  409. /* Reserved space for error reporting in case of memory overflow */
  410. #define ZEND_MM_RESERVE_SIZE (8*1024)
  411. #ifdef _WIN64
  412. # define ZEND_MM_LONG_CONST(x) (x##i64)
  413. #else
  414. # define ZEND_MM_LONG_CONST(x) (x##L)
  415. #endif
  416. #define ZEND_MM_TYPE_MASK ZEND_MM_LONG_CONST(0x3)
  417. #define ZEND_MM_FREE_BLOCK ZEND_MM_LONG_CONST(0x0)
  418. #define ZEND_MM_USED_BLOCK ZEND_MM_LONG_CONST(0x1)
  419. #define ZEND_MM_GUARD_BLOCK ZEND_MM_LONG_CONST(0x3)
  420. #define ZEND_MM_BLOCK(b, type, size) do { \
  421. size_t _size = (size); \
  422. (b)->info._size = (type) | _size; \
  423. ZEND_MM_BLOCK_AT(b, _size)->info._prev = (type) | _size; \
  424. ZEND_MM_SET_COOKIE(b); \
  425. } while (0);
  426. #define ZEND_MM_LAST_BLOCK(b) do { \
  427. (b)->info._size = ZEND_MM_GUARD_BLOCK | ZEND_MM_ALIGNED_HEADER_SIZE; \
  428. ZEND_MM_SET_MAGIC(b, MEM_BLOCK_GUARD); \
  429. } while (0);
  430. #define ZEND_MM_BLOCK_SIZE(b) ((b)->info._size & ~ZEND_MM_TYPE_MASK)
  431. #define ZEND_MM_IS_FREE_BLOCK(b) (!((b)->info._size & ZEND_MM_USED_BLOCK))
  432. #define ZEND_MM_IS_USED_BLOCK(b) ((b)->info._size & ZEND_MM_USED_BLOCK)
  433. #define ZEND_MM_IS_GUARD_BLOCK(b) (((b)->info._size & ZEND_MM_TYPE_MASK) == ZEND_MM_GUARD_BLOCK)
  434. #define ZEND_MM_NEXT_BLOCK(b) ZEND_MM_BLOCK_AT(b, ZEND_MM_BLOCK_SIZE(b))
  435. #define ZEND_MM_PREV_BLOCK(b) ZEND_MM_BLOCK_AT(b, -(ssize_t)((b)->info._prev & ~ZEND_MM_TYPE_MASK))
  436. #define ZEND_MM_PREV_BLOCK_IS_FREE(b) (!((b)->info._prev & ZEND_MM_USED_BLOCK))
  437. #define ZEND_MM_MARK_FIRST_BLOCK(b) ((b)->info._prev = ZEND_MM_GUARD_BLOCK)
  438. #define ZEND_MM_IS_FIRST_BLOCK(b) ((b)->info._prev == ZEND_MM_GUARD_BLOCK)
  439. /* optimized access */
  440. #define ZEND_MM_FREE_BLOCK_SIZE(b) (b)->info._size
  441. /* Aligned header size */
  442. #define ZEND_MM_ALIGNED_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block))
  443. #define ZEND_MM_ALIGNED_FREE_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block))
  444. #define ZEND_MM_MIN_ALLOC_BLOCK_SIZE ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE)
  445. #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)
  446. #define ZEND_MM_ALIGNED_SEGMENT_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_segment))
  447. #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)
  448. #define ZEND_MM_MAX_SMALL_SIZE ((ZEND_MM_NUM_BUCKETS<<ZEND_MM_ALIGNMENT_LOG2)+ZEND_MM_ALIGNED_MIN_HEADER_SIZE)
  449. #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)))
  450. #define ZEND_MM_BUCKET_INDEX(true_size) ((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))
  451. #define ZEND_MM_SMALL_SIZE(true_size) (true_size < ZEND_MM_MAX_SMALL_SIZE)
  452. /* Memory calculations */
  453. #define ZEND_MM_BLOCK_AT(blk, offset) ((zend_mm_block *) (((char *) (blk))+(offset)))
  454. #define ZEND_MM_DATA_OF(p) ((void *) (((char *) (p))+ZEND_MM_ALIGNED_HEADER_SIZE))
  455. #define ZEND_MM_HEADER_OF(blk) ZEND_MM_BLOCK_AT(blk, -(int)ZEND_MM_ALIGNED_HEADER_SIZE)
  456. /* Debug output */
  457. #if ZEND_DEBUG
  458. # ifdef ZTS
  459. # define ZEND_MM_SET_THREAD_ID(block) \
  460. ((zend_mm_block*)(block))->thread_id = tsrm_thread_id()
  461. # define ZEND_MM_BAD_THREAD_ID(block) ((block)->thread_id != tsrm_thread_id())
  462. # else
  463. # define ZEND_MM_SET_THREAD_ID(block)
  464. # define ZEND_MM_BAD_THREAD_ID(block) 0
  465. # endif
  466. # define ZEND_MM_VALID_PTR(block) \
  467. zend_mm_check_ptr(heap, block, 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)
  468. # define ZEND_MM_SET_MAGIC(block, val) do { \
  469. (block)->magic = (val); \
  470. } while (0)
  471. # define ZEND_MM_CHECK_MAGIC(block, val) do { \
  472. if ((block)->magic != (val)) { \
  473. zend_mm_panic("zend_mm_heap corrupted"); \
  474. } \
  475. } while (0)
  476. # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) do { \
  477. ((zend_mm_block*)(block))->debug.filename = __zend_filename; \
  478. ((zend_mm_block*)(block))->debug.lineno = __zend_lineno; \
  479. ((zend_mm_block*)(block))->debug.orig_filename = __zend_orig_filename; \
  480. ((zend_mm_block*)(block))->debug.orig_lineno = __zend_orig_lineno; \
  481. ZEND_MM_SET_BLOCK_SIZE(block, __size); \
  482. if (set_valid) { \
  483. ZEND_MM_SET_MAGIC(block, MEM_BLOCK_VALID); \
  484. } \
  485. if (set_thread) { \
  486. ZEND_MM_SET_THREAD_ID(block); \
  487. } \
  488. } while (0)
  489. #else
  490. # define ZEND_MM_VALID_PTR(ptr) EXPECTED(ptr != NULL)
  491. # define ZEND_MM_SET_MAGIC(block, val)
  492. # define ZEND_MM_CHECK_MAGIC(block, val)
  493. # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) ZEND_MM_SET_BLOCK_SIZE(block, __size)
  494. #endif
  495. #if ZEND_MM_HEAP_PROTECTION
  496. # define ZEND_MM_CHECK_PROTECTION(block) \
  497. do { \
  498. if ((block)->debug.start_magic != _mem_block_start_magic || \
  499. memcmp(ZEND_MM_END_MAGIC_PTR(block), &_mem_block_end_magic, END_MAGIC_SIZE) != 0) { \
  500. zend_mm_panic("zend_mm_heap corrupted"); \
  501. } \
  502. } while (0)
  503. # define ZEND_MM_END_MAGIC_PTR(block) \
  504. (((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->debug.size)
  505. # define END_MAGIC_SIZE sizeof(unsigned int)
  506. # define ZEND_MM_SET_BLOCK_SIZE(block, __size) do { \
  507. char *p; \
  508. ((zend_mm_block*)(block))->debug.size = (__size); \
  509. p = ZEND_MM_END_MAGIC_PTR(block); \
  510. ((zend_mm_block*)(block))->debug.start_magic = _mem_block_start_magic; \
  511. memcpy(p, &_mem_block_end_magic, END_MAGIC_SIZE); \
  512. } while (0)
  513. static unsigned int _mem_block_start_magic = 0;
  514. static unsigned int _mem_block_end_magic = 0;
  515. #else
  516. # if ZEND_DEBUG
  517. # define ZEND_MM_SET_BLOCK_SIZE(block, _size) \
  518. ((zend_mm_block*)(block))->debug.size = (_size)
  519. # else
  520. # define ZEND_MM_SET_BLOCK_SIZE(block, _size)
  521. # endif
  522. # define ZEND_MM_CHECK_PROTECTION(block)
  523. # define END_MAGIC_SIZE 0
  524. #endif
  525. #if ZEND_MM_SAFE_UNLINKING
  526. # define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \
  527. if (UNEXPECTED((block)->info._size != ZEND_MM_BLOCK_AT(block, ZEND_MM_FREE_BLOCK_SIZE(block))->info._prev) || \
  528. UNEXPECTED(!UNEXPECTED(ZEND_MM_IS_FIRST_BLOCK(block)) && \
  529. UNEXPECTED(ZEND_MM_PREV_BLOCK(block)->info._size != (block)->info._prev))) { \
  530. zend_mm_panic("zend_mm_heap corrupted"); \
  531. }
  532. #define ZEND_MM_CHECK_TREE(block) \
  533. if (UNEXPECTED(*((block)->parent) != (block))) { \
  534. zend_mm_panic("zend_mm_heap corrupted"); \
  535. }
  536. #else
  537. # define ZEND_MM_CHECK_BLOCK_LINKAGE(block)
  538. # define ZEND_MM_CHECK_TREE(block)
  539. #endif
  540. #define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)
  541. 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 ZEND_ATTRIBUTE_ALLOC_SIZE(2);
  542. static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
  543. 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_ATTRIBUTE_ALLOC_SIZE(3);
  544. static inline unsigned int zend_mm_high_bit(size_t _size)
  545. {
  546. #if defined(__GNUC__) && (defined(__native_client__) || defined(i386))
  547. unsigned int n;
  548. __asm__("bsrl %1,%0\n\t" : "=r" (n) : "rm" (_size) : "cc");
  549. return n;
  550. #elif defined(__GNUC__) && defined(__x86_64__)
  551. unsigned long n;
  552. __asm__("bsr %1,%0\n\t" : "=r" (n) : "rm" (_size) : "cc");
  553. return (unsigned int)n;
  554. #elif defined(_MSC_VER) && defined(_M_IX86)
  555. __asm {
  556. bsr eax, _size
  557. }
  558. #elif defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))
  559. return (8 * SIZEOF_SIZE_T - 1) - __builtin_clzl(_size);
  560. #else
  561. unsigned int n = 0;
  562. while (_size != 0) {
  563. _size = _size >> 1;
  564. n++;
  565. }
  566. return n-1;
  567. #endif
  568. }
  569. static inline unsigned int zend_mm_low_bit(size_t _size)
  570. {
  571. #if defined(__GNUC__) && (defined(__native_client__) || defined(i386))
  572. unsigned int n;
  573. __asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm" (_size) : "cc");
  574. return n;
  575. #elif defined(__GNUC__) && defined(__x86_64__)
  576. unsigned long n;
  577. __asm__("bsf %1,%0\n\t" : "=r" (n) : "rm" (_size) : "cc");
  578. return (unsigned int)n;
  579. #elif defined(_MSC_VER) && defined(_M_IX86)
  580. __asm {
  581. bsf eax, _size
  582. }
  583. #elif defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))
  584. return __builtin_ctzl(_size);
  585. #else
  586. static const int offset[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
  587. unsigned int n;
  588. unsigned int index = 0;
  589. n = offset[_size & 15];
  590. while (n == 4) {
  591. _size >>= 4;
  592. index += n;
  593. n = offset[_size & 15];
  594. }
  595. return index + n;
  596. #endif
  597. }
  598. static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
  599. {
  600. size_t size;
  601. size_t index;
  602. ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
  603. size = ZEND_MM_FREE_BLOCK_SIZE(mm_block);
  604. if (EXPECTED(!ZEND_MM_SMALL_SIZE(size))) {
  605. zend_mm_free_block **p;
  606. index = ZEND_MM_LARGE_BUCKET_INDEX(size);
  607. p = &heap->large_free_buckets[index];
  608. mm_block->child[0] = mm_block->child[1] = NULL;
  609. if (!*p) {
  610. *p = mm_block;
  611. mm_block->parent = p;
  612. mm_block->prev_free_block = mm_block->next_free_block = mm_block;
  613. heap->large_free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
  614. } else {
  615. size_t m;
  616. for (m = size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
  617. zend_mm_free_block *prev = *p;
  618. if (ZEND_MM_FREE_BLOCK_SIZE(prev) != size) {
  619. p = &prev->child[(m >> (ZEND_MM_NUM_BUCKETS-1)) & 1];
  620. if (!*p) {
  621. *p = mm_block;
  622. mm_block->parent = p;
  623. mm_block->prev_free_block = mm_block->next_free_block = mm_block;
  624. break;
  625. }
  626. } else {
  627. zend_mm_free_block *next = prev->next_free_block;
  628. prev->next_free_block = next->prev_free_block = mm_block;
  629. mm_block->next_free_block = next;
  630. mm_block->prev_free_block = prev;
  631. mm_block->parent = NULL;
  632. break;
  633. }
  634. }
  635. }
  636. } else {
  637. zend_mm_free_block *prev, *next;
  638. index = ZEND_MM_BUCKET_INDEX(size);
  639. prev = ZEND_MM_SMALL_FREE_BUCKET(heap, index);
  640. if (prev->prev_free_block == prev) {
  641. heap->free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
  642. }
  643. next = prev->next_free_block;
  644. mm_block->prev_free_block = prev;
  645. mm_block->next_free_block = next;
  646. prev->next_free_block = next->prev_free_block = mm_block;
  647. }
  648. }
  649. static inline void zend_mm_remove_from_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
  650. {
  651. zend_mm_free_block *prev = mm_block->prev_free_block;
  652. zend_mm_free_block *next = mm_block->next_free_block;
  653. ZEND_MM_CHECK_MAGIC(mm_block, MEM_BLOCK_FREED);
  654. if (EXPECTED(prev == mm_block)) {
  655. zend_mm_free_block **rp, **cp;
  656. #if ZEND_MM_SAFE_UNLINKING
  657. if (UNEXPECTED(next != mm_block)) {
  658. zend_mm_panic("zend_mm_heap corrupted");
  659. }
  660. #endif
  661. rp = &mm_block->child[mm_block->child[1] != NULL];
  662. prev = *rp;
  663. if (EXPECTED(prev == NULL)) {
  664. size_t index = ZEND_MM_LARGE_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
  665. ZEND_MM_CHECK_TREE(mm_block);
  666. *mm_block->parent = NULL;
  667. if (mm_block->parent == &heap->large_free_buckets[index]) {
  668. heap->large_free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
  669. }
  670. } else {
  671. while (*(cp = &(prev->child[prev->child[1] != NULL])) != NULL) {
  672. prev = *cp;
  673. rp = cp;
  674. }
  675. *rp = NULL;
  676. subst_block:
  677. ZEND_MM_CHECK_TREE(mm_block);
  678. *mm_block->parent = prev;
  679. prev->parent = mm_block->parent;
  680. if ((prev->child[0] = mm_block->child[0])) {
  681. ZEND_MM_CHECK_TREE(prev->child[0]);
  682. prev->child[0]->parent = &prev->child[0];
  683. }
  684. if ((prev->child[1] = mm_block->child[1])) {
  685. ZEND_MM_CHECK_TREE(prev->child[1]);
  686. prev->child[1]->parent = &prev->child[1];
  687. }
  688. }
  689. } else {
  690. #if ZEND_MM_SAFE_UNLINKING
  691. if (UNEXPECTED(prev->next_free_block != mm_block) || UNEXPECTED(next->prev_free_block != mm_block)) {
  692. zend_mm_panic("zend_mm_heap corrupted");
  693. }
  694. #endif
  695. prev->next_free_block = next;
  696. next->prev_free_block = prev;
  697. if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block)))) {
  698. if (EXPECTED(prev == next)) {
  699. size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
  700. if (EXPECTED(heap->free_buckets[index*2] == heap->free_buckets[index*2+1])) {
  701. heap->free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
  702. }
  703. }
  704. } else if (UNEXPECTED(mm_block->parent == ZEND_MM_REST_BLOCK)) {
  705. heap->rest_count--;
  706. } else if (UNEXPECTED(mm_block->parent != NULL)) {
  707. goto subst_block;
  708. }
  709. }
  710. }
  711. static inline void zend_mm_add_to_rest_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
  712. {
  713. zend_mm_free_block *prev, *next;
  714. while (heap->rest_count >= ZEND_MM_MAX_REST_BLOCKS) {
  715. zend_mm_free_block *p = heap->rest_buckets[1];
  716. if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(p))) {
  717. heap->rest_count--;
  718. }
  719. prev = p->prev_free_block;
  720. next = p->next_free_block;
  721. prev->next_free_block = next;
  722. next->prev_free_block = prev;
  723. zend_mm_add_to_free_list(heap, p);
  724. }
  725. if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block))) {
  726. mm_block->parent = ZEND_MM_REST_BLOCK;
  727. heap->rest_count++;
  728. }
  729. ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
  730. prev = heap->rest_buckets[0];
  731. next = prev->next_free_block;
  732. mm_block->prev_free_block = prev;
  733. mm_block->next_free_block = next;
  734. prev->next_free_block = next->prev_free_block = mm_block;
  735. }
  736. static inline void zend_mm_init(zend_mm_heap *heap)
  737. {
  738. zend_mm_free_block* p;
  739. int i;
  740. heap->free_bitmap = 0;
  741. heap->large_free_bitmap = 0;
  742. #if ZEND_MM_CACHE
  743. heap->cached = 0;
  744. memset(heap->cache, 0, sizeof(heap->cache));
  745. #endif
  746. #if ZEND_MM_CACHE_STAT
  747. for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
  748. heap->cache_stat[i].count = 0;
  749. }
  750. #endif
  751. p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
  752. for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
  753. p->next_free_block = p;
  754. p->prev_free_block = p;
  755. p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
  756. heap->large_free_buckets[i] = NULL;
  757. }
  758. heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap);
  759. heap->rest_count = 0;
  760. }
  761. static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment)
  762. {
  763. zend_mm_segment **p = &heap->segments_list;
  764. while (*p != segment) {
  765. p = &(*p)->next_segment;
  766. }
  767. *p = segment->next_segment;
  768. heap->real_size -= segment->size;
  769. ZEND_MM_STORAGE_FREE(segment);
  770. }
  771. #if ZEND_MM_CACHE
  772. static void zend_mm_free_cache(zend_mm_heap *heap)
  773. {
  774. int i;
  775. for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
  776. if (heap->cache[i]) {
  777. zend_mm_free_block *mm_block = heap->cache[i];
  778. while (mm_block) {
  779. size_t size = ZEND_MM_BLOCK_SIZE(mm_block);
  780. zend_mm_free_block *q = mm_block->prev_free_block;
  781. zend_mm_block *next_block = ZEND_MM_NEXT_BLOCK(mm_block);
  782. heap->cached -= size;
  783. if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
  784. mm_block = (zend_mm_free_block*)ZEND_MM_PREV_BLOCK(mm_block);
  785. size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
  786. zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
  787. }
  788. if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
  789. size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
  790. zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
  791. }
  792. ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
  793. if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
  794. ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_NEXT_BLOCK(mm_block))) {
  795. zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
  796. } else {
  797. zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
  798. }
  799. mm_block = q;
  800. }
  801. heap->cache[i] = NULL;
  802. #if ZEND_MM_CACHE_STAT
  803. heap->cache_stat[i].count = 0;
  804. #endif
  805. }
  806. }
  807. }
  808. #endif
  809. #if ZEND_MM_HEAP_PROTECTION || ZEND_MM_COOKIES
  810. static void zend_mm_random(unsigned char *buf, size_t size) /* {{{ */
  811. {
  812. size_t i = 0;
  813. unsigned char t;
  814. #ifdef ZEND_WIN32
  815. HCRYPTPROV hCryptProv;
  816. int has_context = 0;
  817. if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
  818. /* Could mean that the key container does not exist, let try
  819. again by asking for a new one */
  820. if (GetLastError() == NTE_BAD_KEYSET) {
  821. if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
  822. has_context = 1;
  823. }
  824. }
  825. } else {
  826. has_context = 1;
  827. }
  828. if (has_context) {
  829. do {
  830. BOOL ret = CryptGenRandom(hCryptProv, size, buf);
  831. CryptReleaseContext(hCryptProv, 0);
  832. if (ret) {
  833. while (i < size && buf[i] != 0) {
  834. i++;
  835. }
  836. if (i == size) {
  837. return;
  838. }
  839. }
  840. } while (0);
  841. }
  842. #elif defined(HAVE_DEV_URANDOM)
  843. int fd = open("/dev/urandom", 0);
  844. if (fd >= 0) {
  845. if (read(fd, buf, size) == size) {
  846. while (i < size && buf[i] != 0) {
  847. i++;
  848. }
  849. if (i == size) {
  850. close(fd);
  851. return;
  852. }
  853. }
  854. close(fd);
  855. }
  856. #endif
  857. t = (unsigned char)getpid();
  858. while (i < size) {
  859. do {
  860. buf[i] = ((unsigned char)rand()) ^ t;
  861. } while (buf[i] == 0);
  862. t = buf[i++] << 1;
  863. }
  864. }
  865. /* }}} */
  866. #endif
  867. /* Notes:
  868. * - This function may alter the block_sizes values to match platform alignment
  869. * - This function does *not* perform sanity checks on the arguments
  870. */
  871. 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)
  872. {
  873. zend_mm_storage *storage;
  874. zend_mm_heap *heap;
  875. #if 0
  876. int i;
  877. printf("ZEND_MM_ALIGNMENT=%d\n", ZEND_MM_ALIGNMENT);
  878. printf("ZEND_MM_ALIGNMENT_LOG2=%d\n", ZEND_MM_ALIGNMENT_LOG2);
  879. printf("ZEND_MM_MIN_SIZE=%d\n", ZEND_MM_MIN_SIZE);
  880. printf("ZEND_MM_MAX_SMALL_SIZE=%d\n", ZEND_MM_MAX_SMALL_SIZE);
  881. printf("ZEND_MM_ALIGNED_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_HEADER_SIZE);
  882. printf("ZEND_MM_ALIGNED_FREE_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_FREE_HEADER_SIZE);
  883. printf("ZEND_MM_MIN_ALLOC_BLOCK_SIZE=%d\n", ZEND_MM_MIN_ALLOC_BLOCK_SIZE);
  884. printf("ZEND_MM_ALIGNED_MIN_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_MIN_HEADER_SIZE);
  885. printf("ZEND_MM_ALIGNED_SEGMENT_SIZE=%d\n", ZEND_MM_ALIGNED_SEGMENT_SIZE);
  886. for (i = 0; i < ZEND_MM_MAX_SMALL_SIZE; i++) {
  887. 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)));
  888. }
  889. exit(0);
  890. #endif
  891. #if ZEND_MM_HEAP_PROTECTION
  892. if (_mem_block_start_magic == 0) {
  893. zend_mm_random((unsigned char*)&_mem_block_start_magic, sizeof(_mem_block_start_magic));
  894. }
  895. if (_mem_block_end_magic == 0) {
  896. zend_mm_random((unsigned char*)&_mem_block_end_magic, sizeof(_mem_block_end_magic));
  897. }
  898. #endif
  899. #if ZEND_MM_COOKIES
  900. if (_zend_mm_cookie == 0) {
  901. zend_mm_random((unsigned char*)&_zend_mm_cookie, sizeof(_zend_mm_cookie));
  902. }
  903. #endif
  904. if (zend_mm_low_bit(block_size) != zend_mm_high_bit(block_size)) {
  905. fprintf(stderr, "'block_size' must be a power of two\n");
  906. /* See http://support.microsoft.com/kb/190351 */
  907. #ifdef PHP_WIN32
  908. fflush(stderr);
  909. #endif
  910. exit(255);
  911. }
  912. storage = handlers->init(params);
  913. if (!storage) {
  914. fprintf(stderr, "Cannot initialize zend_mm storage [%s]\n", handlers->name);
  915. /* See http://support.microsoft.com/kb/190351 */
  916. #ifdef PHP_WIN32
  917. fflush(stderr);
  918. #endif
  919. exit(255);
  920. }
  921. storage->handlers = handlers;
  922. heap = malloc(sizeof(struct _zend_mm_heap));
  923. if (heap == NULL) {
  924. fprintf(stderr, "Cannot allocate heap for zend_mm storage [%s]\n", handlers->name);
  925. #ifdef PHP_WIN32
  926. fflush(stderr);
  927. #endif
  928. exit(255);
  929. }
  930. heap->storage = storage;
  931. heap->block_size = block_size;
  932. heap->compact_size = 0;
  933. heap->segments_list = NULL;
  934. zend_mm_init(heap);
  935. # if ZEND_MM_CACHE_STAT
  936. memset(heap->cache_stat, 0, sizeof(heap->cache_stat));
  937. # endif
  938. heap->use_zend_alloc = 1;
  939. heap->real_size = 0;
  940. heap->overflow = 0;
  941. heap->real_peak = 0;
  942. heap->limit = ZEND_MM_LONG_CONST(1)<<(ZEND_MM_NUM_BUCKETS-2);
  943. heap->size = 0;
  944. heap->peak = 0;
  945. heap->internal = internal;
  946. heap->reserve = NULL;
  947. heap->reserve_size = reserve_size;
  948. if (reserve_size > 0) {
  949. heap->reserve = _zend_mm_alloc_int(heap, reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
  950. }
  951. if (internal) {
  952. int i;
  953. zend_mm_free_block *p, *q, *orig;
  954. zend_mm_heap *mm_heap = _zend_mm_alloc_int(heap, sizeof(zend_mm_heap) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
  955. *mm_heap = *heap;
  956. p = ZEND_MM_SMALL_FREE_BUCKET(mm_heap, 0);
  957. orig = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
  958. for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
  959. q = p;
  960. while (q->prev_free_block != orig) {
  961. q = q->prev_free_block;
  962. }
  963. q->prev_free_block = p;
  964. q = p;
  965. while (q->next_free_block != orig) {
  966. q = q->next_free_block;
  967. }
  968. q->next_free_block = p;
  969. p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
  970. orig = (zend_mm_free_block*)((char*)orig + sizeof(zend_mm_free_block*) * 2);
  971. if (mm_heap->large_free_buckets[i]) {
  972. mm_heap->large_free_buckets[i]->parent = &mm_heap->large_free_buckets[i];
  973. }
  974. }
  975. mm_heap->rest_buckets[0] = mm_heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(mm_heap);
  976. mm_heap->rest_count = 0;
  977. free(heap);
  978. heap = mm_heap;
  979. }
  980. return heap;
  981. }
  982. ZEND_API zend_mm_heap *zend_mm_startup(void)
  983. {
  984. int i;
  985. size_t seg_size;
  986. char *mem_type = getenv("ZEND_MM_MEM_TYPE");
  987. char *tmp;
  988. const zend_mm_mem_handlers *handlers;
  989. zend_mm_heap *heap;
  990. if (mem_type == NULL) {
  991. i = 0;
  992. } else {
  993. for (i = 0; mem_handlers[i].name; i++) {
  994. if (strcmp(mem_handlers[i].name, mem_type) == 0) {
  995. break;
  996. }
  997. }
  998. if (!mem_handlers[i].name) {
  999. fprintf(stderr, "Wrong or unsupported zend_mm storage type '%s'\n", mem_type);
  1000. fprintf(stderr, " supported types:\n");
  1001. /* See http://support.microsoft.com/kb/190351 */
  1002. #ifdef PHP_WIN32
  1003. fflush(stderr);
  1004. #endif
  1005. for (i = 0; mem_handlers[i].name; i++) {
  1006. fprintf(stderr, " '%s'\n", mem_handlers[i].name);
  1007. }
  1008. /* See http://support.microsoft.com/kb/190351 */
  1009. #ifdef PHP_WIN32
  1010. fflush(stderr);
  1011. #endif
  1012. exit(255);
  1013. }
  1014. }
  1015. handlers = &mem_handlers[i];
  1016. tmp = getenv("ZEND_MM_SEG_SIZE");
  1017. if (tmp) {
  1018. seg_size = zend_atoi(tmp, 0);
  1019. if (zend_mm_low_bit(seg_size) != zend_mm_high_bit(seg_size)) {
  1020. fprintf(stderr, "ZEND_MM_SEG_SIZE must be a power of two\n");
  1021. /* See http://support.microsoft.com/kb/190351 */
  1022. #ifdef PHP_WIN32
  1023. fflush(stderr);
  1024. #endif
  1025. exit(255);
  1026. } else if (seg_size < ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE) {
  1027. fprintf(stderr, "ZEND_MM_SEG_SIZE is too small\n");
  1028. /* See http://support.microsoft.com/kb/190351 */
  1029. #ifdef PHP_WIN32
  1030. fflush(stderr);
  1031. #endif
  1032. exit(255);
  1033. }
  1034. } else {
  1035. seg_size = ZEND_MM_SEG_SIZE;
  1036. }
  1037. heap = zend_mm_startup_ex(handlers, seg_size, ZEND_MM_RESERVE_SIZE, 0, NULL);
  1038. if (heap) {
  1039. tmp = getenv("ZEND_MM_COMPACT");
  1040. if (tmp) {
  1041. heap->compact_size = zend_atoi(tmp, 0);
  1042. } else {
  1043. heap->compact_size = 2 * 1024 * 1024;
  1044. }
  1045. }
  1046. return heap;
  1047. }
  1048. #if ZEND_DEBUG
  1049. static long zend_mm_find_leaks(zend_mm_segment *segment, zend_mm_block *b)
  1050. {
  1051. long leaks = 0;
  1052. zend_mm_block *p, *q;
  1053. p = ZEND_MM_NEXT_BLOCK(b);
  1054. while (1) {
  1055. if (ZEND_MM_IS_GUARD_BLOCK(p)) {
  1056. ZEND_MM_CHECK_MAGIC(p, MEM_BLOCK_GUARD);
  1057. segment = segment->next_segment;
  1058. if (!segment) {
  1059. break;
  1060. }
  1061. p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1062. continue;
  1063. }
  1064. q = ZEND_MM_NEXT_BLOCK(p);
  1065. if (q <= p ||
  1066. (char*)q > (char*)segment + segment->size ||
  1067. p->info._size != q->info._prev) {
  1068. zend_mm_panic("zend_mm_heap corrupted");
  1069. }
  1070. if (!ZEND_MM_IS_FREE_BLOCK(p)) {
  1071. if (p->magic == MEM_BLOCK_VALID) {
  1072. if (p->debug.filename==b->debug.filename && p->debug.lineno==b->debug.lineno) {
  1073. ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK);
  1074. leaks++;
  1075. }
  1076. #if ZEND_MM_CACHE
  1077. } else if (p->magic == MEM_BLOCK_CACHED) {
  1078. /* skip it */
  1079. #endif
  1080. } else if (p->magic != MEM_BLOCK_LEAK) {
  1081. zend_mm_panic("zend_mm_heap corrupted");
  1082. }
  1083. }
  1084. p = q;
  1085. }
  1086. return leaks;
  1087. }
  1088. static void zend_mm_check_leaks(zend_mm_heap *heap TSRMLS_DC)
  1089. {
  1090. zend_mm_segment *segment = heap->segments_list;
  1091. zend_mm_block *p, *q;
  1092. zend_uint total = 0;
  1093. if (!segment) {
  1094. return;
  1095. }
  1096. p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1097. while (1) {
  1098. q = ZEND_MM_NEXT_BLOCK(p);
  1099. if (q <= p ||
  1100. (char*)q > (char*)segment + segment->size ||
  1101. p->info._size != q->info._prev) {
  1102. zend_mm_panic("zend_mm_heap corrupted");
  1103. }
  1104. if (!ZEND_MM_IS_FREE_BLOCK(p)) {
  1105. if (p->magic == MEM_BLOCK_VALID) {
  1106. long repeated;
  1107. zend_leak_info leak;
  1108. ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK);
  1109. leak.addr = ZEND_MM_DATA_OF(p);
  1110. leak.size = p->debug.size;
  1111. leak.filename = p->debug.filename;
  1112. leak.lineno = p->debug.lineno;
  1113. leak.orig_filename = p->debug.orig_filename;
  1114. leak.orig_lineno = p->debug.orig_lineno;
  1115. zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
  1116. zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, &leak TSRMLS_CC);
  1117. repeated = zend_mm_find_leaks(segment, p);
  1118. total += 1 + repeated;
  1119. if (repeated) {
  1120. zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(zend_uintptr_t)repeated TSRMLS_CC);
  1121. }
  1122. #if ZEND_MM_CACHE
  1123. } else if (p->magic == MEM_BLOCK_CACHED) {
  1124. /* skip it */
  1125. #endif
  1126. } else if (p->magic != MEM_BLOCK_LEAK) {
  1127. zend_mm_panic("zend_mm_heap corrupted");
  1128. }
  1129. }
  1130. if (ZEND_MM_IS_GUARD_BLOCK(q)) {
  1131. segment = segment->next_segment;
  1132. if (!segment) {
  1133. break;
  1134. }
  1135. q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1136. }
  1137. p = q;
  1138. }
  1139. if (total) {
  1140. zend_message_dispatcher(ZMSG_MEMORY_LEAKS_GRAND_TOTAL, &total TSRMLS_CC);
  1141. }
  1142. }
  1143. static int zend_mm_check_ptr(zend_mm_heap *heap, void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  1144. {
  1145. zend_mm_block *p;
  1146. int no_cache_notice = 0;
  1147. int had_problems = 0;
  1148. int valid_beginning = 1;
  1149. if (silent==2) {
  1150. silent = 1;
  1151. no_cache_notice = 1;
  1152. } else if (silent==3) {
  1153. silent = 0;
  1154. no_cache_notice = 1;
  1155. }
  1156. if (!silent) {
  1157. TSRMLS_FETCH();
  1158. zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
  1159. zend_debug_alloc_output("---------------------------------------\n");
  1160. zend_debug_alloc_output("%s(%d) : Block "PTR_FMT" status:\n" ZEND_FILE_LINE_RELAY_CC, ptr);
  1161. if (__zend_orig_filename) {
  1162. zend_debug_alloc_output("%s(%d) : Actual location (location was relayed)\n" ZEND_FILE_LINE_ORIG_RELAY_CC);
  1163. }
  1164. if (!ptr) {
  1165. zend_debug_alloc_output("NULL\n");
  1166. zend_debug_alloc_output("---------------------------------------\n");
  1167. return 0;
  1168. }
  1169. }
  1170. if (!ptr) {
  1171. if (silent) {
  1172. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1173. }
  1174. }
  1175. p = ZEND_MM_HEADER_OF(ptr);
  1176. #ifdef ZTS
  1177. if (ZEND_MM_BAD_THREAD_ID(p)) {
  1178. if (!silent) {
  1179. zend_debug_alloc_output("Invalid pointer: ((thread_id=0x%0.8X) != (expected=0x%0.8X))\n", (long)p->thread_id, (long)tsrm_thread_id());
  1180. had_problems = 1;
  1181. } else {
  1182. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1183. }
  1184. }
  1185. #endif
  1186. if (p->info._size != ZEND_MM_NEXT_BLOCK(p)->info._prev) {
  1187. if (!silent) {
  1188. zend_debug_alloc_output("Invalid pointer: ((size="PTR_FMT") != (next.prev="PTR_FMT"))\n", p->info._size, ZEND_MM_NEXT_BLOCK(p)->info._prev);
  1189. had_problems = 1;
  1190. } else {
  1191. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1192. }
  1193. }
  1194. if (p->info._prev != ZEND_MM_GUARD_BLOCK &&
  1195. ZEND_MM_PREV_BLOCK(p)->info._size != p->info._prev) {
  1196. if (!silent) {
  1197. zend_debug_alloc_output("Invalid pointer: ((prev="PTR_FMT") != (prev.size="PTR_FMT"))\n", p->info._prev, ZEND_MM_PREV_BLOCK(p)->info._size);
  1198. had_problems = 1;
  1199. } else {
  1200. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1201. }
  1202. }
  1203. if (had_problems) {
  1204. zend_debug_alloc_output("---------------------------------------\n");
  1205. return 0;
  1206. }
  1207. if (!silent) {
  1208. zend_debug_alloc_output("%10s\t","Beginning: ");
  1209. }
  1210. if (!ZEND_MM_IS_USED_BLOCK(p)) {
  1211. if (!silent) {
  1212. if (p->magic != MEM_BLOCK_FREED) {
  1213. zend_debug_alloc_output("Freed (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
  1214. } else {
  1215. zend_debug_alloc_output("Freed\n");
  1216. }
  1217. had_problems = 1;
  1218. } else {
  1219. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1220. }
  1221. } else if (ZEND_MM_IS_GUARD_BLOCK(p)) {
  1222. if (!silent) {
  1223. if (p->magic != MEM_BLOCK_FREED) {
  1224. zend_debug_alloc_output("Guard (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
  1225. } else {
  1226. zend_debug_alloc_output("Guard\n");
  1227. }
  1228. had_problems = 1;
  1229. } else {
  1230. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1231. }
  1232. } else {
  1233. switch (p->magic) {
  1234. case MEM_BLOCK_VALID:
  1235. case MEM_BLOCK_LEAK:
  1236. if (!silent) {
  1237. zend_debug_alloc_output("OK (allocated on %s:%d, %d bytes)\n", p->debug.filename, p->debug.lineno, (int)p->debug.size);
  1238. }
  1239. break; /* ok */
  1240. case MEM_BLOCK_CACHED:
  1241. if (!no_cache_notice) {
  1242. if (!silent) {
  1243. zend_debug_alloc_output("Cached\n");
  1244. had_problems = 1;
  1245. } else {
  1246. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1247. }
  1248. }
  1249. case MEM_BLOCK_FREED:
  1250. if (!silent) {
  1251. zend_debug_alloc_output("Freed (invalid)\n");
  1252. had_problems = 1;
  1253. } else {
  1254. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1255. }
  1256. break;
  1257. case MEM_BLOCK_GUARD:
  1258. if (!silent) {
  1259. zend_debug_alloc_output("Guard (invalid)\n");
  1260. had_problems = 1;
  1261. } else {
  1262. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1263. }
  1264. break;
  1265. default:
  1266. if (!silent) {
  1267. zend_debug_alloc_output("Unknown (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_VALID);
  1268. had_problems = 1;
  1269. valid_beginning = 0;
  1270. } else {
  1271. return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1272. }
  1273. break;
  1274. }
  1275. }
  1276. #if ZEND_MM_HEAP_PROTECTION
  1277. if (!valid_beginning) {
  1278. if (!silent) {
  1279. zend_debug_alloc_output("%10s\t", "Start:");
  1280. zend_debug_alloc_output("Unknown\n");
  1281. zend_debug_alloc_output("%10s\t", "End:");
  1282. zend_debug_alloc_output("Unknown\n");
  1283. }
  1284. } else {
  1285. char *end_magic = ZEND_MM_END_MAGIC_PTR(p);
  1286. if (p->debug.start_magic == _mem_block_start_magic) {
  1287. if (!silent) {
  1288. zend_debug_alloc_output("%10s\t", "Start:");
  1289. zend_debug_alloc_output("OK\n");
  1290. }
  1291. } else {
  1292. char *overflow_ptr, *magic_ptr=(char *) &_mem_block_start_magic;
  1293. int overflows=0;
  1294. int i;
  1295. if (silent) {
  1296. return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1297. }
  1298. had_problems = 1;
  1299. overflow_ptr = (char *) &p->debug.start_magic;
  1300. i = END_MAGIC_SIZE;
  1301. while (--i >= 0) {
  1302. if (overflow_ptr[i]!=magic_ptr[i]) {
  1303. overflows++;
  1304. }
  1305. }
  1306. zend_debug_alloc_output("%10s\t", "Start:");
  1307. zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", p->debug.start_magic, _mem_block_start_magic);
  1308. zend_debug_alloc_output("%10s\t","");
  1309. if (overflows >= END_MAGIC_SIZE) {
  1310. zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
  1311. } else {
  1312. zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
  1313. }
  1314. }
  1315. if (memcmp(end_magic, &_mem_block_end_magic, END_MAGIC_SIZE)==0) {
  1316. if (!silent) {
  1317. zend_debug_alloc_output("%10s\t", "End:");
  1318. zend_debug_alloc_output("OK\n");
  1319. }
  1320. } else {
  1321. char *overflow_ptr, *magic_ptr=(char *) &_mem_block_end_magic;
  1322. int overflows=0;
  1323. int i;
  1324. if (silent) {
  1325. return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1326. }
  1327. had_problems = 1;
  1328. overflow_ptr = (char *) end_magic;
  1329. for (i=0; i < END_MAGIC_SIZE; i++) {
  1330. if (overflow_ptr[i]!=magic_ptr[i]) {
  1331. overflows++;
  1332. }
  1333. }
  1334. zend_debug_alloc_output("%10s\t", "End:");
  1335. zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", *end_magic, _mem_block_end_magic);
  1336. zend_debug_alloc_output("%10s\t","");
  1337. if (overflows >= END_MAGIC_SIZE) {
  1338. zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
  1339. } else {
  1340. zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
  1341. }
  1342. }
  1343. }
  1344. #endif
  1345. if (!silent) {
  1346. zend_debug_alloc_output("---------------------------------------\n");
  1347. }
  1348. return ((!had_problems) ? 1 : 0);
  1349. }
  1350. static int zend_mm_check_heap(zend_mm_heap *heap, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  1351. {
  1352. zend_mm_segment *segment = heap->segments_list;
  1353. zend_mm_block *p, *q;
  1354. int errors = 0;
  1355. if (!segment) {
  1356. return 0;
  1357. }
  1358. p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1359. while (1) {
  1360. q = ZEND_MM_NEXT_BLOCK(p);
  1361. if (q <= p ||
  1362. (char*)q > (char*)segment + segment->size ||
  1363. p->info._size != q->info._prev) {
  1364. zend_mm_panic("zend_mm_heap corrupted");
  1365. }
  1366. if (!ZEND_MM_IS_FREE_BLOCK(p)) {
  1367. if (p->magic == MEM_BLOCK_VALID || p->magic == MEM_BLOCK_LEAK) {
  1368. 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)) {
  1369. errors++;
  1370. }
  1371. #if ZEND_MM_CACHE
  1372. } else if (p->magic == MEM_BLOCK_CACHED) {
  1373. /* skip it */
  1374. #endif
  1375. } else if (p->magic != MEM_BLOCK_LEAK) {
  1376. zend_mm_panic("zend_mm_heap corrupted");
  1377. }
  1378. }
  1379. if (ZEND_MM_IS_GUARD_BLOCK(q)) {
  1380. segment = segment->next_segment;
  1381. if (!segment) {
  1382. return errors;
  1383. }
  1384. q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1385. }
  1386. p = q;
  1387. }
  1388. }
  1389. #endif
  1390. ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, int full_shutdown, int silent TSRMLS_DC)
  1391. {
  1392. zend_mm_storage *storage;
  1393. zend_mm_segment *segment;
  1394. zend_mm_segment *prev;
  1395. int internal;
  1396. if (!heap->use_zend_alloc) {
  1397. if (full_shutdown) {
  1398. free(heap);
  1399. }
  1400. return;
  1401. }
  1402. if (heap->reserve) {
  1403. #if ZEND_DEBUG
  1404. if (!silent) {
  1405. _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
  1406. }
  1407. #endif
  1408. heap->reserve = NULL;
  1409. }
  1410. #if ZEND_MM_CACHE_STAT
  1411. if (full_shutdown) {
  1412. FILE *f;
  1413. f = fopen("zend_mm.log", "w");
  1414. if (f) {
  1415. int i,j;
  1416. size_t size, true_size, min_size, max_size;
  1417. int hit = 0, miss = 0;
  1418. fprintf(f, "\nidx min_size max_size true_size max_len hits misses\n");
  1419. size = 0;
  1420. while (1) {
  1421. true_size = ZEND_MM_TRUE_SIZE(size);
  1422. if (ZEND_MM_SMALL_SIZE(true_size)) {
  1423. min_size = size;
  1424. i = ZEND_MM_BUCKET_INDEX(true_size);
  1425. size++;
  1426. while (1) {
  1427. true_size = ZEND_MM_TRUE_SIZE(size);
  1428. if (ZEND_MM_SMALL_SIZE(true_size)) {
  1429. j = ZEND_MM_BUCKET_INDEX(true_size);
  1430. if (j > i) {
  1431. max_size = size-1;
  1432. break;
  1433. }
  1434. } else {
  1435. max_size = size-1;
  1436. break;
  1437. }
  1438. size++;
  1439. }
  1440. hit += heap->cache_stat[i].hit;
  1441. miss += heap->cache_stat[i].miss;
  1442. 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);
  1443. } else {
  1444. break;
  1445. }
  1446. }
  1447. fprintf(f, " %8d %8d\n", hit, miss);
  1448. fprintf(f, " %8d %8d\n", heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit, heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss);
  1449. fclose(f);
  1450. }
  1451. }
  1452. #endif
  1453. #if ZEND_DEBUG
  1454. if (!silent) {
  1455. zend_mm_check_leaks(heap TSRMLS_CC);
  1456. }
  1457. #endif
  1458. internal = heap->internal;
  1459. storage = heap->storage;
  1460. segment = heap->segments_list;
  1461. if (full_shutdown) {
  1462. while (segment) {
  1463. prev = segment;
  1464. segment = segment->next_segment;
  1465. ZEND_MM_STORAGE_FREE(prev);
  1466. }
  1467. heap->segments_list = NULL;
  1468. storage->handlers->dtor(storage);
  1469. if (!internal) {
  1470. free(heap);
  1471. }
  1472. } else {
  1473. if (segment) {
  1474. #ifndef ZEND_WIN32
  1475. if (heap->reserve_size) {
  1476. while (segment->next_segment) {
  1477. prev = segment;
  1478. segment = segment->next_segment;
  1479. ZEND_MM_STORAGE_FREE(prev);
  1480. }
  1481. heap->segments_list = segment;
  1482. } else {
  1483. #endif
  1484. do {
  1485. prev = segment;
  1486. segment = segment->next_segment;
  1487. ZEND_MM_STORAGE_FREE(prev);
  1488. } while (segment);
  1489. heap->segments_list = NULL;
  1490. #ifndef ZEND_WIN32
  1491. }
  1492. #endif
  1493. }
  1494. if (heap->compact_size &&
  1495. heap->real_peak > heap->compact_size) {
  1496. storage->handlers->compact(storage);
  1497. }
  1498. zend_mm_init(heap);
  1499. if (heap->segments_list) {
  1500. heap->real_size = heap->segments_list->size;
  1501. heap->real_peak = heap->segments_list->size;
  1502. } else {
  1503. heap->real_size = 0;
  1504. heap->real_peak = 0;
  1505. }
  1506. heap->size = 0;
  1507. heap->peak = 0;
  1508. if (heap->segments_list) {
  1509. /* mark segment as a free block */
  1510. zend_mm_free_block *b = (zend_mm_free_block*)((char*)heap->segments_list + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1511. size_t block_size = heap->segments_list->size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
  1512. ZEND_MM_MARK_FIRST_BLOCK(b);
  1513. ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(b, block_size));
  1514. ZEND_MM_BLOCK(b, ZEND_MM_FREE_BLOCK, block_size);
  1515. zend_mm_add_to_free_list(heap, b);
  1516. }
  1517. if (heap->reserve_size) {
  1518. heap->reserve = _zend_mm_alloc_int(heap, heap->reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
  1519. }
  1520. heap->overflow = 0;
  1521. }
  1522. }
  1523. static void zend_mm_safe_error(zend_mm_heap *heap,
  1524. const char *format,
  1525. size_t limit,
  1526. #if ZEND_DEBUG
  1527. const char *filename,
  1528. uint lineno,
  1529. #endif
  1530. size_t size)
  1531. {
  1532. if (heap->reserve) {
  1533. _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
  1534. heap->reserve = NULL;
  1535. }
  1536. if (heap->overflow == 0) {
  1537. const char *error_filename;
  1538. uint error_lineno;
  1539. TSRMLS_FETCH();
  1540. if (zend_is_compiling(TSRMLS_C)) {
  1541. error_filename = zend_get_compiled_filename(TSRMLS_C);
  1542. error_lineno = zend_get_compiled_lineno(TSRMLS_C);
  1543. } else if (EG(in_execution)) {
  1544. error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL;
  1545. error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0;
  1546. } else {
  1547. error_filename = NULL;
  1548. error_lineno = 0;
  1549. }
  1550. if (!error_filename) {
  1551. error_filename = "Unknown";
  1552. }
  1553. heap->overflow = 1;
  1554. zend_try {
  1555. zend_error_noreturn(E_ERROR,
  1556. format,
  1557. limit,
  1558. #if ZEND_DEBUG
  1559. filename,
  1560. lineno,
  1561. #endif
  1562. size);
  1563. } zend_catch {
  1564. if (heap->overflow == 2) {
  1565. fprintf(stderr, "\nFatal error: ");
  1566. fprintf(stderr,
  1567. format,
  1568. limit,
  1569. #if ZEND_DEBUG
  1570. filename,
  1571. lineno,
  1572. #endif
  1573. size);
  1574. fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno);
  1575. }
  1576. /* See http://support.microsoft.com/kb/190351 */
  1577. #ifdef PHP_WIN32
  1578. fflush(stderr);
  1579. #endif
  1580. } zend_end_try();
  1581. } else {
  1582. heap->overflow = 2;
  1583. }
  1584. zend_bailout();
  1585. }
  1586. static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size)
  1587. {
  1588. zend_mm_free_block *best_fit;
  1589. size_t index = ZEND_MM_LARGE_BUCKET_INDEX(true_size);
  1590. size_t bitmap = heap->large_free_bitmap >> index;
  1591. zend_mm_free_block *p;
  1592. if (bitmap == 0) {
  1593. return NULL;
  1594. }
  1595. if (UNEXPECTED((bitmap & 1) != 0)) {
  1596. /* Search for best "large" free block */
  1597. zend_mm_free_block *rst = NULL;
  1598. size_t m;
  1599. size_t best_size = -1;
  1600. best_fit = NULL;
  1601. p = heap->large_free_buckets[index];
  1602. for (m = true_size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
  1603. if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
  1604. return p->next_free_block;
  1605. } else if (ZEND_MM_FREE_BLOCK_SIZE(p) >= true_size &&
  1606. ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
  1607. best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
  1608. best_fit = p;
  1609. }
  1610. if ((m & (ZEND_MM_LONG_CONST(1) << (ZEND_MM_NUM_BUCKETS-1))) == 0) {
  1611. if (p->child[1]) {
  1612. rst = p->child[1];
  1613. }
  1614. if (p->child[0]) {
  1615. p = p->child[0];
  1616. } else {
  1617. break;
  1618. }
  1619. } else if (p->child[1]) {
  1620. p = p->child[1];
  1621. } else {
  1622. break;
  1623. }
  1624. }
  1625. for (p = rst; p; p = p->child[p->child[0] != NULL]) {
  1626. if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
  1627. return p->next_free_block;
  1628. } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
  1629. ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
  1630. best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
  1631. best_fit = p;
  1632. }
  1633. }
  1634. if (best_fit) {
  1635. return best_fit->next_free_block;
  1636. }
  1637. bitmap = bitmap >> 1;
  1638. if (!bitmap) {
  1639. return NULL;
  1640. }
  1641. index++;
  1642. }
  1643. /* Search for smallest "large" free block */
  1644. best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];
  1645. while ((p = p->child[p->child[0] != NULL])) {
  1646. if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit)) {
  1647. best_fit = p;
  1648. }
  1649. }
  1650. return best_fit->next_free_block;
  1651. }
  1652. static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  1653. {
  1654. zend_mm_free_block *best_fit;
  1655. size_t true_size = ZEND_MM_TRUE_SIZE(size);
  1656. size_t block_size;
  1657. size_t remaining_size;
  1658. size_t segment_size;
  1659. zend_mm_segment *segment;
  1660. int keep_rest = 0;
  1661. #ifdef ZEND_SIGNALS
  1662. TSRMLS_FETCH();
  1663. #endif
  1664. HANDLE_BLOCK_INTERRUPTIONS();
  1665. if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) {
  1666. size_t index = ZEND_MM_BUCKET_INDEX(true_size);
  1667. size_t bitmap;
  1668. if (UNEXPECTED(true_size < size)) {
  1669. goto out_of_memory;
  1670. }
  1671. #if ZEND_MM_CACHE
  1672. if (EXPECTED(heap->cache[index] != NULL)) {
  1673. /* Get block from cache */
  1674. #if ZEND_MM_CACHE_STAT
  1675. heap->cache_stat[index].count--;
  1676. heap->cache_stat[index].hit++;
  1677. #endif
  1678. best_fit = heap->cache[index];
  1679. heap->cache[index] = best_fit->prev_free_block;
  1680. heap->cached -= true_size;
  1681. ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
  1682. ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
  1683. HANDLE_UNBLOCK_INTERRUPTIONS();
  1684. return ZEND_MM_DATA_OF(best_fit);
  1685. }
  1686. #if ZEND_MM_CACHE_STAT
  1687. heap->cache_stat[index].miss++;
  1688. #endif
  1689. #endif
  1690. bitmap = heap->free_bitmap >> index;
  1691. if (bitmap) {
  1692. /* Found some "small" free block that can be used */
  1693. index += zend_mm_low_bit(bitmap);
  1694. best_fit = heap->free_buckets[index*2];
  1695. #if ZEND_MM_CACHE_STAT
  1696. heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit++;
  1697. #endif
  1698. goto zend_mm_finished_searching_for_block;
  1699. }
  1700. }
  1701. #if ZEND_MM_CACHE_STAT
  1702. heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss++;
  1703. #endif
  1704. best_fit = zend_mm_search_large_block(heap, true_size);
  1705. if (!best_fit && heap->real_size >= heap->limit - heap->block_size) {
  1706. zend_mm_free_block *p = heap->rest_buckets[0];
  1707. size_t best_size = -1;
  1708. while (p != ZEND_MM_REST_BUCKET(heap)) {
  1709. if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
  1710. best_fit = p;
  1711. goto zend_mm_finished_searching_for_block;
  1712. } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
  1713. ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
  1714. best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
  1715. best_fit = p;
  1716. }
  1717. p = p->prev_free_block;
  1718. }
  1719. }
  1720. if (!best_fit) {
  1721. if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
  1722. /* Make sure we add a memory block which is big enough,
  1723. segment must have header "size" and trailer "guard" block */
  1724. segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE;
  1725. segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
  1726. keep_rest = 1;
  1727. } else {
  1728. segment_size = heap->block_size;
  1729. }
  1730. if (segment_size < true_size ||
  1731. heap->real_size + segment_size > heap->limit) {
  1732. /* Memory limit overflow */
  1733. #if ZEND_MM_CACHE
  1734. zend_mm_free_cache(heap);
  1735. #endif
  1736. HANDLE_UNBLOCK_INTERRUPTIONS();
  1737. #if ZEND_DEBUG
  1738. 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);
  1739. #else
  1740. zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes)", heap->limit, size);
  1741. #endif
  1742. }
  1743. segment = (zend_mm_segment *) ZEND_MM_STORAGE_ALLOC(segment_size);
  1744. if (!segment) {
  1745. /* Storage manager cannot allocate memory */
  1746. #if ZEND_MM_CACHE
  1747. zend_mm_free_cache(heap);
  1748. #endif
  1749. out_of_memory:
  1750. HANDLE_UNBLOCK_INTERRUPTIONS();
  1751. #if ZEND_DEBUG
  1752. 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);
  1753. #else
  1754. zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %lu bytes)", heap->real_size, size);
  1755. #endif
  1756. return NULL;
  1757. }
  1758. heap->real_size += segment_size;
  1759. if (heap->real_size > heap->real_peak) {
  1760. heap->real_peak = heap->real_size;
  1761. }
  1762. segment->size = segment_size;
  1763. segment->next_segment = heap->segments_list;
  1764. heap->segments_list = segment;
  1765. best_fit = (zend_mm_free_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1766. ZEND_MM_MARK_FIRST_BLOCK(best_fit);
  1767. block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
  1768. ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(best_fit, block_size));
  1769. } else {
  1770. zend_mm_finished_searching_for_block:
  1771. /* remove from free list */
  1772. ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED);
  1773. ZEND_MM_CHECK_COOKIE(best_fit);
  1774. ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit);
  1775. zend_mm_remove_from_free_list(heap, best_fit);
  1776. block_size = ZEND_MM_FREE_BLOCK_SIZE(best_fit);
  1777. }
  1778. remaining_size = block_size - true_size;
  1779. if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
  1780. true_size = block_size;
  1781. ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
  1782. } else {
  1783. zend_mm_free_block *new_free_block;
  1784. /* prepare new free block */
  1785. ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
  1786. new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(best_fit, true_size);
  1787. ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
  1788. /* add the new free block to the free list */
  1789. if (EXPECTED(!keep_rest)) {
  1790. zend_mm_add_to_free_list(heap, new_free_block);
  1791. } else {
  1792. zend_mm_add_to_rest_list(heap, new_free_block);
  1793. }
  1794. }
  1795. ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1);
  1796. heap->size += true_size;
  1797. if (heap->peak < heap->size) {
  1798. heap->peak = heap->size;
  1799. }
  1800. HANDLE_UNBLOCK_INTERRUPTIONS();
  1801. return ZEND_MM_DATA_OF(best_fit);
  1802. }
  1803. static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  1804. {
  1805. zend_mm_block *mm_block;
  1806. zend_mm_block *next_block;
  1807. size_t size;
  1808. #ifdef ZEND_SIGNALS
  1809. TSRMLS_FETCH();
  1810. #endif
  1811. if (!ZEND_MM_VALID_PTR(p)) {
  1812. return;
  1813. }
  1814. HANDLE_BLOCK_INTERRUPTIONS();
  1815. mm_block = ZEND_MM_HEADER_OF(p);
  1816. size = ZEND_MM_BLOCK_SIZE(mm_block);
  1817. ZEND_MM_CHECK_PROTECTION(mm_block);
  1818. #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
  1819. memset(ZEND_MM_DATA_OF(mm_block), 0x5a, mm_block->debug.size);
  1820. #endif
  1821. #if ZEND_MM_CACHE
  1822. if (EXPECTED(ZEND_MM_SMALL_SIZE(size)) && EXPECTED(heap->cached < ZEND_MM_CACHE_SIZE)) {
  1823. size_t index = ZEND_MM_BUCKET_INDEX(size);
  1824. zend_mm_free_block **cache = &heap->cache[index];
  1825. ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
  1826. *cache = (zend_mm_free_block*)mm_block;
  1827. heap->cached += size;
  1828. ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
  1829. #if ZEND_MM_CACHE_STAT
  1830. if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
  1831. heap->cache_stat[index].max_count = heap->cache_stat[index].count;
  1832. }
  1833. #endif
  1834. HANDLE_UNBLOCK_INTERRUPTIONS();
  1835. return;
  1836. }
  1837. #endif
  1838. heap->size -= size;
  1839. next_block = ZEND_MM_BLOCK_AT(mm_block, size);
  1840. if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
  1841. zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
  1842. size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
  1843. }
  1844. if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
  1845. mm_block = ZEND_MM_PREV_BLOCK(mm_block);
  1846. zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
  1847. size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
  1848. }
  1849. if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
  1850. ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(mm_block, size))) {
  1851. zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
  1852. } else {
  1853. ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
  1854. zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
  1855. }
  1856. HANDLE_UNBLOCK_INTERRUPTIONS();
  1857. }
  1858. static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  1859. {
  1860. zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p);
  1861. zend_mm_block *next_block;
  1862. size_t true_size;
  1863. size_t orig_size;
  1864. void *ptr;
  1865. #ifdef ZEND_SIGNALS
  1866. TSRMLS_FETCH();
  1867. #endif
  1868. if (UNEXPECTED(!p) || !ZEND_MM_VALID_PTR(p)) {
  1869. return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  1870. }
  1871. HANDLE_BLOCK_INTERRUPTIONS();
  1872. mm_block = ZEND_MM_HEADER_OF(p);
  1873. true_size = ZEND_MM_TRUE_SIZE(size);
  1874. orig_size = ZEND_MM_BLOCK_SIZE(mm_block);
  1875. ZEND_MM_CHECK_PROTECTION(mm_block);
  1876. if (UNEXPECTED(true_size < size)) {
  1877. goto out_of_memory;
  1878. }
  1879. if (true_size <= orig_size) {
  1880. size_t remaining_size = orig_size - true_size;
  1881. if (remaining_size >= ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
  1882. zend_mm_free_block *new_free_block;
  1883. next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
  1884. if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
  1885. remaining_size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
  1886. zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
  1887. }
  1888. /* prepare new free block */
  1889. ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
  1890. new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
  1891. ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
  1892. /* add the new free block to the free list */
  1893. zend_mm_add_to_free_list(heap, new_free_block);
  1894. heap->size += (true_size - orig_size);
  1895. }
  1896. ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
  1897. HANDLE_UNBLOCK_INTERRUPTIONS();
  1898. return p;
  1899. }
  1900. #if ZEND_MM_CACHE
  1901. if (ZEND_MM_SMALL_SIZE(true_size)) {
  1902. size_t index = ZEND_MM_BUCKET_INDEX(true_size);
  1903. if (heap->cache[index] != NULL) {
  1904. zend_mm_free_block *best_fit;
  1905. zend_mm_free_block **cache;
  1906. #if ZEND_MM_CACHE_STAT
  1907. heap->cache_stat[index].count--;
  1908. heap->cache_stat[index].hit++;
  1909. #endif
  1910. best_fit = heap->cache[index];
  1911. heap->cache[index] = best_fit->prev_free_block;
  1912. ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
  1913. ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
  1914. ptr = ZEND_MM_DATA_OF(best_fit);
  1915. #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
  1916. memcpy(ptr, p, mm_block->debug.size);
  1917. #else
  1918. memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
  1919. #endif
  1920. heap->cached -= true_size - orig_size;
  1921. index = ZEND_MM_BUCKET_INDEX(orig_size);
  1922. cache = &heap->cache[index];
  1923. ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
  1924. *cache = (zend_mm_free_block*)mm_block;
  1925. ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
  1926. #if ZEND_MM_CACHE_STAT
  1927. if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
  1928. heap->cache_stat[index].max_count = heap->cache_stat[index].count;
  1929. }
  1930. #endif
  1931. HANDLE_UNBLOCK_INTERRUPTIONS();
  1932. return ptr;
  1933. }
  1934. }
  1935. #endif
  1936. next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
  1937. if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
  1938. ZEND_MM_CHECK_COOKIE(next_block);
  1939. ZEND_MM_CHECK_BLOCK_LINKAGE(next_block);
  1940. if (orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block) >= true_size) {
  1941. size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block);
  1942. size_t remaining_size = block_size - true_size;
  1943. zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
  1944. if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
  1945. true_size = block_size;
  1946. ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
  1947. } else {
  1948. zend_mm_free_block *new_free_block;
  1949. /* prepare new free block */
  1950. ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
  1951. new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
  1952. ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
  1953. /* add the new free block to the free list */
  1954. if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
  1955. ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(new_free_block, remaining_size))) {
  1956. zend_mm_add_to_rest_list(heap, new_free_block);
  1957. } else {
  1958. zend_mm_add_to_free_list(heap, new_free_block);
  1959. }
  1960. }
  1961. ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
  1962. heap->size = heap->size + true_size - orig_size;
  1963. if (heap->peak < heap->size) {
  1964. heap->peak = heap->size;
  1965. }
  1966. HANDLE_UNBLOCK_INTERRUPTIONS();
  1967. return p;
  1968. } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
  1969. ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(next_block, ZEND_MM_FREE_BLOCK_SIZE(next_block)))) {
  1970. zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
  1971. goto realloc_segment;
  1972. }
  1973. } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && ZEND_MM_IS_GUARD_BLOCK(next_block)) {
  1974. zend_mm_segment *segment;
  1975. zend_mm_segment *segment_copy;
  1976. size_t segment_size;
  1977. size_t block_size;
  1978. size_t remaining_size;
  1979. realloc_segment:
  1980. /* segment size, size of block and size of guard block */
  1981. if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
  1982. segment_size = true_size+ZEND_MM_ALIGNED_SEGMENT_SIZE+ZEND_MM_ALIGNED_HEADER_SIZE;
  1983. segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
  1984. } else {
  1985. segment_size = heap->block_size;
  1986. }
  1987. segment_copy = (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE);
  1988. if (segment_size < true_size ||
  1989. heap->real_size + segment_size - segment_copy->size > heap->limit) {
  1990. if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
  1991. zend_mm_add_to_free_list(heap, (zend_mm_free_block *) next_block);
  1992. }
  1993. #if ZEND_MM_CACHE
  1994. zend_mm_free_cache(heap);
  1995. #endif
  1996. HANDLE_UNBLOCK_INTERRUPTIONS();
  1997. #if ZEND_DEBUG
  1998. 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);
  1999. #else
  2000. zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %ld bytes)", heap->limit, size);
  2001. #endif
  2002. return NULL;
  2003. }
  2004. segment = ZEND_MM_STORAGE_REALLOC(segment_copy, segment_size);
  2005. if (!segment) {
  2006. #if ZEND_MM_CACHE
  2007. zend_mm_free_cache(heap);
  2008. #endif
  2009. out_of_memory:
  2010. HANDLE_UNBLOCK_INTERRUPTIONS();
  2011. #if ZEND_DEBUG
  2012. 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);
  2013. #else
  2014. zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %ld bytes)", heap->real_size, size);
  2015. #endif
  2016. return NULL;
  2017. }
  2018. heap->real_size += segment_size - segment->size;
  2019. if (heap->real_size > heap->real_peak) {
  2020. heap->real_peak = heap->real_size;
  2021. }
  2022. segment->size = segment_size;
  2023. if (segment != segment_copy) {
  2024. zend_mm_segment **seg = &heap->segments_list;
  2025. while (*seg != segment_copy) {
  2026. seg = &(*seg)->next_segment;
  2027. }
  2028. *seg = segment;
  2029. mm_block = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
  2030. ZEND_MM_MARK_FIRST_BLOCK(mm_block);
  2031. }
  2032. block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
  2033. remaining_size = block_size - true_size;
  2034. /* setup guard block */
  2035. ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(mm_block, block_size));
  2036. if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
  2037. true_size = block_size;
  2038. ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
  2039. } else {
  2040. zend_mm_free_block *new_free_block;
  2041. /* prepare new free block */
  2042. ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
  2043. new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
  2044. ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
  2045. /* add the new free block to the free list */
  2046. zend_mm_add_to_rest_list(heap, new_free_block);
  2047. }
  2048. ZEND_MM_SET_DEBUG_INFO(mm_block, size, 1, 1);
  2049. heap->size = heap->size + true_size - orig_size;
  2050. if (heap->peak < heap->size) {
  2051. heap->peak = heap->size;
  2052. }
  2053. HANDLE_UNBLOCK_INTERRUPTIONS();
  2054. return ZEND_MM_DATA_OF(mm_block);
  2055. }
  2056. ptr = _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2057. #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
  2058. memcpy(ptr, p, mm_block->debug.size);
  2059. #else
  2060. memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
  2061. #endif
  2062. _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2063. HANDLE_UNBLOCK_INTERRUPTIONS();
  2064. return ptr;
  2065. }
  2066. ZEND_API void *_zend_mm_alloc(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2067. {
  2068. return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2069. }
  2070. ZEND_API void _zend_mm_free(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2071. {
  2072. _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2073. }
  2074. ZEND_API void *_zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2075. {
  2076. return _zend_mm_realloc_int(heap, ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2077. }
  2078. ZEND_API size_t _zend_mm_block_size(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2079. {
  2080. zend_mm_block *mm_block;
  2081. if (!ZEND_MM_VALID_PTR(p)) {
  2082. return 0;
  2083. }
  2084. mm_block = ZEND_MM_HEADER_OF(p);
  2085. ZEND_MM_CHECK_PROTECTION(mm_block);
  2086. #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
  2087. return mm_block->debug.size;
  2088. #else
  2089. return ZEND_MM_BLOCK_SIZE(mm_block);
  2090. #endif
  2091. }
  2092. /**********************/
  2093. /* Allocation Manager */
  2094. /**********************/
  2095. typedef struct _zend_alloc_globals {
  2096. zend_mm_heap *mm_heap;
  2097. } zend_alloc_globals;
  2098. #ifdef ZTS
  2099. static int alloc_globals_id;
  2100. # define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v)
  2101. #else
  2102. # define AG(v) (alloc_globals.v)
  2103. static zend_alloc_globals alloc_globals;
  2104. #endif
  2105. ZEND_API int is_zend_mm(TSRMLS_D)
  2106. {
  2107. return AG(mm_heap)->use_zend_alloc;
  2108. }
  2109. ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2110. {
  2111. TSRMLS_FETCH();
  2112. if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
  2113. return AG(mm_heap)->_malloc(size);
  2114. }
  2115. return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2116. }
  2117. ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2118. {
  2119. TSRMLS_FETCH();
  2120. if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
  2121. AG(mm_heap)->_free(ptr);
  2122. return;
  2123. }
  2124. _zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2125. }
  2126. ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2127. {
  2128. TSRMLS_FETCH();
  2129. if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
  2130. return AG(mm_heap)->_realloc(ptr, size);
  2131. }
  2132. return _zend_mm_realloc_int(AG(mm_heap), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2133. }
  2134. ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2135. {
  2136. if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
  2137. return 0;
  2138. }
  2139. return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2140. }
  2141. #if defined(__GNUC__) && (defined(__native_client__) || defined(i386))
  2142. static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
  2143. {
  2144. size_t res = nmemb;
  2145. unsigned long overflow = 0;
  2146. __asm__ ("mull %3\n\taddl %4,%0\n\tadcl $0,%1"
  2147. : "=&a"(res), "=&d" (overflow)
  2148. : "%0"(res),
  2149. "rm"(size),
  2150. "rm"(offset));
  2151. if (UNEXPECTED(overflow)) {
  2152. zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
  2153. return 0;
  2154. }
  2155. return res;
  2156. }
  2157. #elif defined(__GNUC__) && defined(__x86_64__)
  2158. static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
  2159. {
  2160. size_t res = nmemb;
  2161. unsigned long overflow = 0;
  2162. #ifdef __ILP32__ /* x32 */
  2163. # define LP_SUFF "l"
  2164. #else /* amd64 */
  2165. # define LP_SUFF "q"
  2166. #endif
  2167. __asm__ ("mul" LP_SUFF " %3\n\t"
  2168. "add %4,%0\n\t"
  2169. "adc $0,%1"
  2170. : "=&a"(res), "=&d" (overflow)
  2171. : "%0"(res),
  2172. "rm"(size),
  2173. "rm"(offset));
  2174. #undef LP_SUFF
  2175. if (UNEXPECTED(overflow)) {
  2176. zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
  2177. return 0;
  2178. }
  2179. return res;
  2180. }
  2181. #elif defined(__GNUC__) && defined(__arm__)
  2182. static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
  2183. {
  2184. size_t res;
  2185. unsigned long overflow;
  2186. __asm__ ("umlal %0,%1,%2,%3"
  2187. : "=r"(res), "=r"(overflow)
  2188. : "r"(nmemb),
  2189. "r"(size),
  2190. "0"(offset),
  2191. "1"(0));
  2192. if (UNEXPECTED(overflow)) {
  2193. zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
  2194. return 0;
  2195. }
  2196. return res;
  2197. }
  2198. #elif defined(__GNUC__) && defined(__aarch64__)
  2199. static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
  2200. {
  2201. size_t res;
  2202. unsigned long overflow;
  2203. __asm__ ("mul %0,%2,%3\n\tumulh %1,%2,%3\n\tadds %0,%0,%4\n\tadc %1,%1,xzr"
  2204. : "=&r"(res), "=&r"(overflow)
  2205. : "r"(nmemb),
  2206. "r"(size),
  2207. "r"(offset));
  2208. if (UNEXPECTED(overflow)) {
  2209. zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
  2210. return 0;
  2211. }
  2212. return res;
  2213. }
  2214. #elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64)
  2215. static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
  2216. {
  2217. zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset;
  2218. if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) {
  2219. zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
  2220. return 0;
  2221. }
  2222. return (size_t) res;
  2223. }
  2224. #else
  2225. static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
  2226. {
  2227. size_t res = nmemb * size + offset;
  2228. double _d = (double)nmemb * (double)size + (double)offset;
  2229. double _delta = (double)res - _d;
  2230. if (UNEXPECTED((_d + _delta ) != _d)) {
  2231. zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
  2232. return 0;
  2233. }
  2234. return res;
  2235. }
  2236. #endif
  2237. ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2238. {
  2239. return emalloc_rel(safe_address(nmemb, size, offset));
  2240. }
  2241. ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset)
  2242. {
  2243. return pemalloc(safe_address(nmemb, size, offset), 1);
  2244. }
  2245. 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)
  2246. {
  2247. return erealloc_rel(ptr, safe_address(nmemb, size, offset));
  2248. }
  2249. ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset)
  2250. {
  2251. return perealloc(ptr, safe_address(nmemb, size, offset), 1);
  2252. }
  2253. ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2254. {
  2255. void *p;
  2256. #ifdef ZEND_SIGNALS
  2257. TSRMLS_FETCH();
  2258. #endif
  2259. HANDLE_BLOCK_INTERRUPTIONS();
  2260. p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2261. if (UNEXPECTED(p == NULL)) {
  2262. HANDLE_UNBLOCK_INTERRUPTIONS();
  2263. return p;
  2264. }
  2265. memset(p, 0, size * nmemb);
  2266. HANDLE_UNBLOCK_INTERRUPTIONS();
  2267. return p;
  2268. }
  2269. ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2270. {
  2271. int length;
  2272. char *p;
  2273. #ifdef ZEND_SIGNALS
  2274. TSRMLS_FETCH();
  2275. #endif
  2276. HANDLE_BLOCK_INTERRUPTIONS();
  2277. length = strlen(s)+1;
  2278. p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2279. if (UNEXPECTED(p == NULL)) {
  2280. HANDLE_UNBLOCK_INTERRUPTIONS();
  2281. return p;
  2282. }
  2283. memcpy(p, s, length);
  2284. HANDLE_UNBLOCK_INTERRUPTIONS();
  2285. return p;
  2286. }
  2287. ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2288. {
  2289. char *p;
  2290. #ifdef ZEND_SIGNALS
  2291. TSRMLS_FETCH();
  2292. #endif
  2293. HANDLE_BLOCK_INTERRUPTIONS();
  2294. p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2295. if (UNEXPECTED(p == NULL)) {
  2296. HANDLE_UNBLOCK_INTERRUPTIONS();
  2297. return p;
  2298. }
  2299. memcpy(p, s, length);
  2300. p[length] = 0;
  2301. HANDLE_UNBLOCK_INTERRUPTIONS();
  2302. return p;
  2303. }
  2304. ZEND_API char *zend_strndup(const char *s, uint length)
  2305. {
  2306. char *p;
  2307. #ifdef ZEND_SIGNALS
  2308. TSRMLS_FETCH();
  2309. #endif
  2310. HANDLE_BLOCK_INTERRUPTIONS();
  2311. p = (char *) malloc(length+1);
  2312. if (UNEXPECTED(p == NULL)) {
  2313. HANDLE_UNBLOCK_INTERRUPTIONS();
  2314. return p;
  2315. }
  2316. if (length) {
  2317. memcpy(p, s, length);
  2318. }
  2319. p[length] = 0;
  2320. HANDLE_UNBLOCK_INTERRUPTIONS();
  2321. return p;
  2322. }
  2323. ZEND_API int zend_set_memory_limit(size_t memory_limit)
  2324. {
  2325. TSRMLS_FETCH();
  2326. AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
  2327. return SUCCESS;
  2328. }
  2329. ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC)
  2330. {
  2331. if (real_usage) {
  2332. return AG(mm_heap)->real_size;
  2333. } else {
  2334. size_t usage = AG(mm_heap)->size;
  2335. #if ZEND_MM_CACHE
  2336. usage -= AG(mm_heap)->cached;
  2337. #endif
  2338. return usage;
  2339. }
  2340. }
  2341. ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC)
  2342. {
  2343. if (real_usage) {
  2344. return AG(mm_heap)->real_peak;
  2345. } else {
  2346. return AG(mm_heap)->peak;
  2347. }
  2348. }
  2349. ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC)
  2350. {
  2351. zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC);
  2352. }
  2353. static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC)
  2354. {
  2355. char *tmp = getenv("USE_ZEND_ALLOC");
  2356. if (tmp && !zend_atoi(tmp, 0)) {
  2357. alloc_globals->mm_heap = malloc(sizeof(struct _zend_mm_heap));
  2358. memset(alloc_globals->mm_heap, 0, sizeof(struct _zend_mm_heap));
  2359. alloc_globals->mm_heap->use_zend_alloc = 0;
  2360. alloc_globals->mm_heap->_malloc = malloc;
  2361. alloc_globals->mm_heap->_free = free;
  2362. alloc_globals->mm_heap->_realloc = realloc;
  2363. } else {
  2364. alloc_globals->mm_heap = zend_mm_startup();
  2365. }
  2366. }
  2367. #ifdef ZTS
  2368. static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC)
  2369. {
  2370. shutdown_memory_manager(1, 1 TSRMLS_CC);
  2371. }
  2372. #endif
  2373. ZEND_API void start_memory_manager(TSRMLS_D)
  2374. {
  2375. #ifdef ZTS
  2376. ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
  2377. #else
  2378. alloc_globals_ctor(&alloc_globals);
  2379. #endif
  2380. }
  2381. ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap TSRMLS_DC)
  2382. {
  2383. zend_mm_heap *old_heap;
  2384. old_heap = AG(mm_heap);
  2385. AG(mm_heap) = new_heap;
  2386. return old_heap;
  2387. }
  2388. ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
  2389. {
  2390. return heap->storage;
  2391. }
  2392. ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
  2393. void* (*_malloc)(size_t),
  2394. void (*_free)(void*),
  2395. void* (*_realloc)(void*, size_t))
  2396. {
  2397. heap->use_zend_alloc = 0;
  2398. heap->_malloc = _malloc;
  2399. heap->_free = _free;
  2400. heap->_realloc = _realloc;
  2401. }
  2402. #if ZEND_DEBUG
  2403. ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2404. {
  2405. TSRMLS_FETCH();
  2406. if (!AG(mm_heap)->use_zend_alloc) {
  2407. return 1;
  2408. }
  2409. return zend_mm_check_ptr(AG(mm_heap), ptr, silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2410. }
  2411. ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
  2412. {
  2413. int errors;
  2414. TSRMLS_FETCH();
  2415. if (!AG(mm_heap)->use_zend_alloc) {
  2416. return;
  2417. }
  2418. zend_debug_alloc_output("------------------------------------------------\n");
  2419. zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC);
  2420. errors = zend_mm_check_heap(AG(mm_heap), silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
  2421. zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors);
  2422. zend_debug_alloc_output("------------------------------------------------\n");
  2423. }
  2424. #endif
  2425. /*
  2426. * Local variables:
  2427. * tab-width: 4
  2428. * c-basic-offset: 4
  2429. * indent-tabs-mode: t
  2430. * End:
  2431. */