1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % M M EEEEE M M OOO RRRR Y Y % 7 % MM MM E MM MM O O R R Y Y % 8 % M M M EEE M M M O O RRRR Y % 9 % M M E M M O O R R Y % 10 % M M EEEEE M M OOO R R Y % 11 % % 12 % % 13 % MagickCore Memory Allocation Methods % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1998 % 18 % % 19 % % 20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization % 21 % dedicated to making software imaging solutions freely available. % 22 % % 23 % You may not use this file except in compliance with the License. You may % 24 % obtain a copy of the License at % 25 % % 26 % https://imagemagick.org/script/license.php % 27 % % 28 % Unless required by applicable law or agreed to in writing, software % 29 % distributed under the License is distributed on an "AS IS" BASIS, % 30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31 % See the License for the specific language governing permissions and % 32 % limitations under the License. % 33 % % 34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 % 36 % Segregate our memory requirements from any program that calls our API. This 37 % should help reduce the risk of others changing our program state or causing 38 % memory corruption. 39 % 40 % Our custom memory allocation manager implements a best-fit allocation policy 41 % using segregated free lists. It uses a linear distribution of size classes 42 % for lower sizes and a power of two distribution of size classes at higher 43 % sizes. It is based on the paper, "Fast Memory Allocation using Lazy Fits." 44 % written by Yoo C. Chung. 45 % 46 % By default, ANSI memory methods are called (e.g. malloc). Use the 47 % custom memory allocator by defining MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT 48 % to allocate memory with private anonymous mapping rather than from the 49 % heap. 50 % 51 */ 52 53 /* 55 Include declarations. 56 */ 57 #include "MagickCore/studio.h" 58 #include "MagickCore/blob.h" 59 #include "MagickCore/blob-private.h" 60 #include "MagickCore/exception.h" 61 #include "MagickCore/exception-private.h" 62 #include "MagickCore/memory_.h" 63 #include "MagickCore/memory-private.h" 64 #include "MagickCore/policy.h" 65 #include "MagickCore/resource_.h" 66 #include "MagickCore/semaphore.h" 67 #include "MagickCore/string_.h" 68 #include "MagickCore/string-private.h" 69 #include "MagickCore/utility-private.h" 70 71 /* 73 Define declarations. 74 */ 75 #define BlockFooter(block,size) \ 76 ((size_t *) ((char *) (block)+(size)-2*sizeof(size_t))) 77 #define BlockHeader(block) ((size_t *) (block)-1) 78 #define BlockSize 4096 79 #define BlockThreshold 1024 80 #define MaxBlockExponent 16 81 #define MaxBlocks ((BlockThreshold/(4*sizeof(size_t)))+MaxBlockExponent+1) 82 #define MaxSegments 1024 83 #define MemoryGuard ((0xdeadbeef << 31)+0xdeafdeed) 84 #define NextBlock(block) ((char *) (block)+SizeOfBlock(block)) 85 #define NextBlockInList(block) (*(void **) (block)) 86 #define PreviousBlock(block) ((char *) (block)-(*((size_t *) (block)-2))) 87 #define PreviousBlockBit 0x01 88 #define PreviousBlockInList(block) (*((void **) (block)+1)) 89 #define SegmentSize (2*1024*1024) 90 #define SizeMask (~0x01) 91 #define SizeOfBlock(block) (*BlockHeader(block) & SizeMask) 92 93 /* 95 Typedef declarations. 96 */ 97 typedef enum 98 { 99 UndefinedVirtualMemory, 100 AlignedVirtualMemory, 101 MapVirtualMemory, 102 UnalignedVirtualMemory 103 } VirtualMemoryType; 104 105 typedef struct _DataSegmentInfo 106 { 107 void 108 *allocation, 109 *bound; 110 111 MagickBooleanType 112 mapped; 113 114 size_t 115 length; 116 117 struct _DataSegmentInfo 118 *previous, 119 *next; 120 } DataSegmentInfo; 121 122 typedef struct _MagickMemoryMethods 123 { 124 AcquireMemoryHandler 125 acquire_memory_handler; 126 127 ResizeMemoryHandler 128 resize_memory_handler; 129 130 DestroyMemoryHandler 131 destroy_memory_handler; 132 } MagickMemoryMethods; 133 134 struct _MemoryInfo 135 { 136 char 137 filename[MagickPathExtent]; 138 139 VirtualMemoryType 140 type; 141 142 size_t 143 length; 144 145 void 146 *blob; 147 148 size_t 149 signature; 150 }; 151 152 typedef struct _MemoryPool 153 { 154 size_t 155 allocation; 156 157 void 158 *blocks[MaxBlocks+1]; 159 160 size_t 161 number_segments; 162 163 DataSegmentInfo 164 *segments[MaxSegments], 165 segment_pool[MaxSegments]; 166 } MemoryPool; 167 168 /* 170 Global declarations. 171 */ 172 static size_t 173 max_memory_request = 0, 174 virtual_anonymous_memory = 0; 175 176 #if defined _MSC_VER 177 static void* MSCMalloc(size_t size) 178 { 179 return malloc(size); 180 } 181 static void* MSCRealloc(void* ptr, size_t size) 182 { 183 return realloc(ptr, size); 184 } 185 static void MSCFree(void* ptr) 186 { 187 free(ptr); 188 } 189 #endif 190 191 static MagickMemoryMethods 192 memory_methods = 193 { 194 #if defined _MSC_VER 195 (AcquireMemoryHandler) MSCMalloc, 196 (ResizeMemoryHandler) MSCRealloc, 197 (DestroyMemoryHandler) MSCFree 198 #else 199 (AcquireMemoryHandler) malloc, 200 (ResizeMemoryHandler) realloc, 201 (DestroyMemoryHandler) free 202 #endif 203 }; 204 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 205 static MemoryPool 206 memory_pool; 207 208 static SemaphoreInfo 209 *memory_semaphore = (SemaphoreInfo *) NULL; 210 211 static volatile DataSegmentInfo 212 *free_segments = (DataSegmentInfo *) NULL; 213 214 /* 216 Forward declarations. 217 */ 218 static MagickBooleanType 219 ExpandHeap(size_t); 220 #endif 221 222 /* 224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 225 % % 226 % % 227 % % 228 % A c q u i r e A l i g n e d M e m o r y % 229 % % 230 % % 231 % % 232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 233 % 234 % AcquireAlignedMemory() returns a pointer to a block of memory at least size 235 % bytes whose address is aligned on a cache line or page boundary. 236 % 237 % The format of the AcquireAlignedMemory method is: 238 % 239 % void *AcquireAlignedMemory(const size_t count,const size_t quantum) 240 % 241 % A description of each parameter follows: 242 % 243 % o count: the number of quantum elements to allocate. 244 % 245 % o quantum: the number of bytes in each quantum. 246 % 247 */ 248 MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum) 249 { 250 #define AlignedExtent(size,alignment) \ 251 (((size)+((alignment)-1)) & ~((alignment)-1)) 252 #define AlignedPowerOf2(x) ((((x) - 1) & (x)) == 0) 253 254 size_t 255 alignment, 256 extent, 257 size; 258 259 void 260 *memory; 261 262 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse) 263 return((void *) NULL); 264 memory=NULL; 265 size=count*quantum; 266 alignment=CACHE_LINE_SIZE; 267 extent=AlignedExtent(size,alignment); 268 if ((size == 0) || (extent < size)) 269 return((void *) NULL); 270 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN) 271 if (posix_memalign(&memory,alignment,extent) != 0) 272 memory=NULL; 273 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC) 274 memory=_aligned_malloc(extent,alignment); 275 #else 276 { 277 void 278 *p; 279 280 if ((alignment == 0) || (alignment % sizeof(void *) != 0) || 281 (AlignedPowerOf2(alignment/sizeof(void *)) == 0)) 282 { 283 errno=EINVAL; 284 return((void *) NULL); 285 } 286 if (size > (SIZE_MAX-alignment-sizeof(void *)-1)) 287 { 288 errno=ENOMEM; 289 return((void *) NULL); 290 } 291 extent=(size+alignment-1)+sizeof(void *); 292 if (extent > size) 293 { 294 p=malloc(extent); 295 if (p != NULL) 296 { 297 memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment); 298 *((void **) memory-1)=p; 299 } 300 } 301 } 302 #endif 303 return(memory); 304 } 305 306 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 308 /* 309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 310 % % 311 % % 312 % % 313 + A c q u i r e B l o c k % 314 % % 315 % % 316 % % 317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 318 % 319 % AcquireBlock() returns a pointer to a block of memory at least size bytes 320 % suitably aligned for any use. 321 % 322 % The format of the AcquireBlock method is: 323 % 324 % void *AcquireBlock(const size_t size) 325 % 326 % A description of each parameter follows: 327 % 328 % o size: the size of the memory in bytes to allocate. 329 % 330 */ 331 332 static inline size_t AllocationPolicy(size_t size) 333 { 334 register size_t 335 blocksize; 336 337 /* 338 The linear distribution. 339 */ 340 assert(size != 0); 341 assert(size % (4*sizeof(size_t)) == 0); 342 if (size <= BlockThreshold) 343 return(size/(4*sizeof(size_t))); 344 /* 345 Check for the largest block size. 346 */ 347 if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L)))) 348 return(MaxBlocks-1L); 349 /* 350 Otherwise use a power of two distribution. 351 */ 352 blocksize=BlockThreshold/(4*sizeof(size_t)); 353 for ( ; size > BlockThreshold; size/=2) 354 blocksize++; 355 assert(blocksize > (BlockThreshold/(4*sizeof(size_t)))); 356 assert(blocksize < (MaxBlocks-1L)); 357 return(blocksize); 358 } 359 360 static inline void InsertFreeBlock(void *block,const size_t i) 361 { 362 register void 363 *next, 364 *previous; 365 366 size_t 367 size; 368 369 size=SizeOfBlock(block); 370 previous=(void *) NULL; 371 next=memory_pool.blocks[i]; 372 while ((next != (void *) NULL) && (SizeOfBlock(next) < size)) 373 { 374 previous=next; 375 next=NextBlockInList(next); 376 } 377 PreviousBlockInList(block)=previous; 378 NextBlockInList(block)=next; 379 if (previous != (void *) NULL) 380 NextBlockInList(previous)=block; 381 else 382 memory_pool.blocks[i]=block; 383 if (next != (void *) NULL) 384 PreviousBlockInList(next)=block; 385 } 386 387 static inline void RemoveFreeBlock(void *block,const size_t i) 388 { 389 register void 390 *next, 391 *previous; 392 393 next=NextBlockInList(block); 394 previous=PreviousBlockInList(block); 395 if (previous == (void *) NULL) 396 memory_pool.blocks[i]=next; 397 else 398 NextBlockInList(previous)=next; 399 if (next != (void *) NULL) 400 PreviousBlockInList(next)=previous; 401 } 402 403 static void *AcquireBlock(size_t size) 404 { 405 register size_t 406 i; 407 408 register void 409 *block; 410 411 /* 412 Find free block. 413 */ 414 size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t)); 415 i=AllocationPolicy(size); 416 block=memory_pool.blocks[i]; 417 while ((block != (void *) NULL) && (SizeOfBlock(block) < size)) 418 block=NextBlockInList(block); 419 if (block == (void *) NULL) 420 { 421 i++; 422 while (memory_pool.blocks[i] == (void *) NULL) 423 i++; 424 block=memory_pool.blocks[i]; 425 if (i >= MaxBlocks) 426 return((void *) NULL); 427 } 428 assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0); 429 assert(SizeOfBlock(block) >= size); 430 RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block))); 431 if (SizeOfBlock(block) > size) 432 { 433 size_t 434 blocksize; 435 436 void 437 *next; 438 439 /* 440 Split block. 441 */ 442 next=(char *) block+size; 443 blocksize=SizeOfBlock(block)-size; 444 *BlockHeader(next)=blocksize; 445 *BlockFooter(next,blocksize)=blocksize; 446 InsertFreeBlock(next,AllocationPolicy(blocksize)); 447 *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask); 448 } 449 assert(size == SizeOfBlock(block)); 450 *BlockHeader(NextBlock(block))|=PreviousBlockBit; 451 memory_pool.allocation+=size; 452 return(block); 453 } 454 #endif 455 456 /* 458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 459 % % 460 % % 461 % % 462 % A c q u i r e M a g i c k M e m o r y % 463 % % 464 % % 465 % % 466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 467 % 468 % AcquireMagickMemory() returns a pointer to a block of memory at least size 469 % bytes suitably aligned for any use. 470 % 471 % The format of the AcquireMagickMemory method is: 472 % 473 % void *AcquireMagickMemory(const size_t size) 474 % 475 % A description of each parameter follows: 476 % 477 % o size: the size of the memory in bytes to allocate. 478 % 479 */ 480 MagickExport void *AcquireMagickMemory(const size_t size) 481 { 482 register void 483 *memory; 484 485 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 486 memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size); 487 #else 488 if (memory_semaphore == (SemaphoreInfo *) NULL) 489 ActivateSemaphoreInfo(&memory_semaphore); 490 if (free_segments == (DataSegmentInfo *) NULL) 491 { 492 LockSemaphoreInfo(memory_semaphore); 493 if (free_segments == (DataSegmentInfo *) NULL) 494 { 495 register ssize_t 496 i; 497 498 assert(2*sizeof(size_t) > (size_t) (~SizeMask)); 499 (void) memset(&memory_pool,0,sizeof(memory_pool)); 500 memory_pool.allocation=SegmentSize; 501 memory_pool.blocks[MaxBlocks]=(void *) (-1); 502 for (i=0; i < MaxSegments; i++) 503 { 504 if (i != 0) 505 memory_pool.segment_pool[i].previous= 506 (&memory_pool.segment_pool[i-1]); 507 if (i != (MaxSegments-1)) 508 memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]); 509 } 510 free_segments=(&memory_pool.segment_pool[0]); 511 } 512 UnlockSemaphoreInfo(memory_semaphore); 513 } 514 LockSemaphoreInfo(memory_semaphore); 515 memory=AcquireBlock(size == 0 ? 1UL : size); 516 if (memory == (void *) NULL) 517 { 518 if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse) 519 memory=AcquireBlock(size == 0 ? 1UL : size); 520 } 521 UnlockSemaphoreInfo(memory_semaphore); 522 #endif 523 return(memory); 524 } 525 526 /* 528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 529 % % 530 % % 531 % % 532 % A c q u i r e Q u a n t u m M e m o r y % 533 % % 534 % % 535 % % 536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 537 % 538 % AcquireQuantumMemory() returns a pointer to a block of memory at least 539 % count * quantum bytes suitably aligned for any use. 540 % 541 % The format of the AcquireQuantumMemory method is: 542 % 543 % void *AcquireQuantumMemory(const size_t count,const size_t quantum) 544 % 545 % A description of each parameter follows: 546 % 547 % o count: the number of quantum elements to allocate. 548 % 549 % o quantum: the number of bytes in each quantum. 550 % 551 */ 552 MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum) 553 { 554 size_t 555 extent; 556 557 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse) 558 return((void *) NULL); 559 extent=count*quantum; 560 return(AcquireMagickMemory(extent)); 561 } 562 563 /* 565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 566 % % 567 % % 568 % % 569 % A c q u i r e V i r t u a l M e m o r y % 570 % % 571 % % 572 % % 573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 574 % 575 % AcquireVirtualMemory() allocates a pointer to a block of memory at least 576 % size bytes suitably aligned for any use. In addition to heap, it also 577 % supports memory-mapped and file-based memory-mapped memory requests. 578 % 579 % The format of the AcquireVirtualMemory method is: 580 % 581 % MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum) 582 % 583 % A description of each parameter follows: 584 % 585 % o count: the number of quantum elements to allocate. 586 % 587 % o quantum: the number of bytes in each quantum. 588 % 589 */ 590 591 MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count, 592 const size_t quantum) 593 { 594 char 595 *value; 596 597 MemoryInfo 598 *memory_info; 599 600 size_t 601 extent; 602 603 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse) 604 return((MemoryInfo *) NULL); 605 if (virtual_anonymous_memory == 0) 606 { 607 virtual_anonymous_memory=1; 608 value=GetPolicyValue("system:memory-map"); 609 if (LocaleCompare(value,"anonymous") == 0) 610 { 611 /* 612 The security policy sets anonymous mapping for the memory request. 613 */ 614 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS) 615 virtual_anonymous_memory=2; 616 #endif 617 } 618 value=DestroyString(value); 619 } 620 memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1, 621 sizeof(*memory_info))); 622 if (memory_info == (MemoryInfo *) NULL) 623 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 624 (void) memset(memory_info,0,sizeof(*memory_info)); 625 extent=count*quantum; 626 memory_info->length=extent; 627 memory_info->signature=MagickCoreSignature; 628 if ((virtual_anonymous_memory == 1) && 629 ((count*quantum) <= GetMaxMemoryRequest())) 630 { 631 memory_info->blob=AcquireAlignedMemory(1,extent); 632 if (memory_info->blob != NULL) 633 memory_info->type=AlignedVirtualMemory; 634 } 635 if (memory_info->blob == NULL) 636 { 637 /* 638 Acquire anonymous memory map. 639 */ 640 memory_info->blob=NULL; 641 if ((count*quantum) <= GetMaxMemoryRequest()) 642 memory_info->blob=MapBlob(-1,IOMode,0,extent); 643 if (memory_info->blob != NULL) 644 memory_info->type=MapVirtualMemory; 645 else 646 { 647 int 648 file; 649 650 /* 651 Anonymous memory mapping failed, try file-backed memory mapping. 652 */ 653 file=AcquireUniqueFileResource(memory_info->filename); 654 if (file != -1) 655 { 656 MagickOffsetType 657 offset; 658 659 offset=(MagickOffsetType) lseek(file,extent-1,SEEK_SET); 660 if ((offset == (MagickOffsetType) (extent-1)) && 661 (write(file,"",1) == 1)) 662 { 663 #if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE) 664 memory_info->blob=MapBlob(file,IOMode,0,extent); 665 #else 666 if (posix_fallocate(file,0,extent) == 0) 667 memory_info->blob=MapBlob(file,IOMode,0,extent); 668 #endif 669 if (memory_info->blob != NULL) 670 memory_info->type=MapVirtualMemory; 671 else 672 { 673 (void) RelinquishUniqueFileResource( 674 memory_info->filename); 675 *memory_info->filename='\0'; 676 } 677 } 678 (void) close(file); 679 } 680 } 681 } 682 if (memory_info->blob == NULL) 683 { 684 memory_info->blob=AcquireQuantumMemory(1,extent); 685 if (memory_info->blob != NULL) 686 memory_info->type=UnalignedVirtualMemory; 687 } 688 if (memory_info->blob == NULL) 689 memory_info=RelinquishVirtualMemory(memory_info); 690 return(memory_info); 691 } 692 693 /* 695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 696 % % 697 % % 698 % % 699 % C o p y M a g i c k M e m o r y % 700 % % 701 % % 702 % % 703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 704 % 705 % CopyMagickMemory() copies size bytes from memory area source to the 706 % destination. Copying between objects that overlap will take place 707 % correctly. It returns destination. 708 % 709 % The format of the CopyMagickMemory method is: 710 % 711 % void *CopyMagickMemory(void *destination,const void *source, 712 % const size_t size) 713 % 714 % A description of each parameter follows: 715 % 716 % o destination: the destination. 717 % 718 % o source: the source. 719 % 720 % o size: the size of the memory in bytes to allocate. 721 % 722 */ 723 MagickExport void *CopyMagickMemory(void *destination,const void *source, 724 const size_t size) 725 { 726 register const unsigned char 727 *p; 728 729 register unsigned char 730 *q; 731 732 assert(destination != (void *) NULL); 733 assert(source != (const void *) NULL); 734 p=(const unsigned char *) source; 735 q=(unsigned char *) destination; 736 if (((q+size) < p) || (q > (p+size))) 737 switch (size) 738 { 739 default: return(memcpy(destination,source,size)); 740 case 8: *q++=(*p++); 741 case 7: *q++=(*p++); 742 case 6: *q++=(*p++); 743 case 5: *q++=(*p++); 744 case 4: *q++=(*p++); 745 case 3: *q++=(*p++); 746 case 2: *q++=(*p++); 747 case 1: *q++=(*p++); 748 case 0: return(destination); 749 } 750 return(memmove(destination,source,size)); 751 } 752 753 /* 755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 756 % % 757 % % 758 % % 759 + D e s t r o y M a g i c k M e m o r y % 760 % % 761 % % 762 % % 763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 764 % 765 % DestroyMagickMemory() deallocates memory associated with the memory manager. 766 % 767 % The format of the DestroyMagickMemory method is: 768 % 769 % DestroyMagickMemory(void) 770 % 771 */ 772 MagickExport void DestroyMagickMemory(void) 773 { 774 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 775 register ssize_t 776 i; 777 778 if (memory_semaphore == (SemaphoreInfo *) NULL) 779 ActivateSemaphoreInfo(&memory_semaphore); 780 LockSemaphoreInfo(memory_semaphore); 781 for (i=0; i < (ssize_t) memory_pool.number_segments; i++) 782 if (memory_pool.segments[i]->mapped == MagickFalse) 783 memory_methods.destroy_memory_handler( 784 memory_pool.segments[i]->allocation); 785 else 786 (void) UnmapBlob(memory_pool.segments[i]->allocation, 787 memory_pool.segments[i]->length); 788 free_segments=(DataSegmentInfo *) NULL; 789 (void) memset(&memory_pool,0,sizeof(memory_pool)); 790 UnlockSemaphoreInfo(memory_semaphore); 791 RelinquishSemaphoreInfo(&memory_semaphore); 792 #endif 793 } 794 795 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 797 /* 798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 799 % % 800 % % 801 % % 802 + E x p a n d H e a p % 803 % % 804 % % 805 % % 806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 807 % 808 % ExpandHeap() get more memory from the system. It returns MagickTrue on 809 % success otherwise MagickFalse. 810 % 811 % The format of the ExpandHeap method is: 812 % 813 % MagickBooleanType ExpandHeap(size_t size) 814 % 815 % A description of each parameter follows: 816 % 817 % o size: the size of the memory in bytes we require. 818 % 819 */ 820 static MagickBooleanType ExpandHeap(size_t size) 821 { 822 DataSegmentInfo 823 *segment_info; 824 825 MagickBooleanType 826 mapped; 827 828 register ssize_t 829 i; 830 831 register void 832 *block; 833 834 size_t 835 blocksize; 836 837 void 838 *segment; 839 840 blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize; 841 assert(memory_pool.number_segments < MaxSegments); 842 segment=MapBlob(-1,IOMode,0,blocksize); 843 mapped=segment != (void *) NULL ? MagickTrue : MagickFalse; 844 if (segment == (void *) NULL) 845 segment=(void *) memory_methods.acquire_memory_handler(blocksize); 846 if (segment == (void *) NULL) 847 return(MagickFalse); 848 segment_info=(DataSegmentInfo *) free_segments; 849 free_segments=segment_info->next; 850 segment_info->mapped=mapped; 851 segment_info->length=blocksize; 852 segment_info->allocation=segment; 853 segment_info->bound=(char *) segment+blocksize; 854 i=(ssize_t) memory_pool.number_segments-1; 855 for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--) 856 memory_pool.segments[i+1]=memory_pool.segments[i]; 857 memory_pool.segments[i+1]=segment_info; 858 memory_pool.number_segments++; 859 size=blocksize-12*sizeof(size_t); 860 block=(char *) segment_info->allocation+4*sizeof(size_t); 861 *BlockHeader(block)=size | PreviousBlockBit; 862 *BlockFooter(block,size)=size; 863 InsertFreeBlock(block,AllocationPolicy(size)); 864 block=NextBlock(block); 865 assert(block < segment_info->bound); 866 *BlockHeader(block)=2*sizeof(size_t); 867 *BlockHeader(NextBlock(block))=PreviousBlockBit; 868 return(MagickTrue); 869 } 870 #endif 871 872 /* 874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 875 % % 876 % % 877 % % 878 % G e t M a g i c k M e m o r y M e t h o d s % 879 % % 880 % % 881 % % 882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 883 % 884 % GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy 885 % memory. 886 % 887 % The format of the GetMagickMemoryMethods() method is: 888 % 889 % void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler, 890 % ResizeMemoryHandler *resize_memory_handler, 891 % DestroyMemoryHandler *destroy_memory_handler) 892 % 893 % A description of each parameter follows: 894 % 895 % o acquire_memory_handler: method to acquire memory (e.g. malloc). 896 % 897 % o resize_memory_handler: method to resize memory (e.g. realloc). 898 % 899 % o destroy_memory_handler: method to destroy memory (e.g. free). 900 % 901 */ 902 MagickExport void GetMagickMemoryMethods( 903 AcquireMemoryHandler *acquire_memory_handler, 904 ResizeMemoryHandler *resize_memory_handler, 905 DestroyMemoryHandler *destroy_memory_handler) 906 { 907 assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL); 908 assert(resize_memory_handler != (ResizeMemoryHandler *) NULL); 909 assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL); 910 *acquire_memory_handler=memory_methods.acquire_memory_handler; 911 *resize_memory_handler=memory_methods.resize_memory_handler; 912 *destroy_memory_handler=memory_methods.destroy_memory_handler; 913 } 914 915 /* 917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 918 % % 919 % % 920 % % 921 + G e t M a x M e m o r y R e q u e s t % 922 % % 923 % % 924 % % 925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 926 % 927 % GetMaxMemoryRequest() returns the max_memory_request value. 928 % 929 % The format of the GetMaxMemoryRequest method is: 930 % 931 % size_t GetMaxMemoryRequest(void) 932 % 933 */ 934 MagickExport size_t GetMaxMemoryRequest(void) 935 { 936 if (max_memory_request == 0) 937 { 938 char 939 *value; 940 941 value=GetPolicyValue("system:max-memory-request"); 942 if (value != (char *) NULL) 943 { 944 /* 945 The security policy sets a max memory request limit. 946 */ 947 max_memory_request=StringToSizeType(value,100.0); 948 value=DestroyString(value); 949 } 950 else 951 max_memory_request=(size_t) MagickULLConstant(~0); 952 } 953 return(max_memory_request); 954 } 955 956 /* 958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 959 % % 960 % % 961 % % 962 % G e t V i r t u a l M e m o r y B l o b % 963 % % 964 % % 965 % % 966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 967 % 968 % GetVirtualMemoryBlob() returns the virtual memory blob associated with the 969 % specified MemoryInfo structure. 970 % 971 % The format of the GetVirtualMemoryBlob method is: 972 % 973 % void *GetVirtualMemoryBlob(const MemoryInfo *memory_info) 974 % 975 % A description of each parameter follows: 976 % 977 % o memory_info: The MemoryInfo structure. 978 */ 979 MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info) 980 { 981 assert(memory_info != (const MemoryInfo *) NULL); 982 assert(memory_info->signature == MagickCoreSignature); 983 return(memory_info->blob); 984 } 985 986 /* 988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 989 % % 990 % % 991 % % 992 + H e a p O v e r f l o w S a n i t y C h e c k % 993 % % 994 % % 995 % % 996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 997 % 998 % HeapOverflowSanityCheck() returns MagickTrue if the heap allocation request 999 % does not exceed the maximum limits of a size_t otherwise MagickFalse. 1000 % 1001 % The format of the HeapOverflowSanityCheck method is: 1002 % 1003 % MagickBooleanType HeapOverflowSanityCheck(const size_t count, 1004 % const size_t quantum) 1005 % 1006 % A description of each parameter follows: 1007 % 1008 % o size: the size of the memory in bytes we require. 1009 % 1010 */ 1011 MagickExport MagickBooleanType HeapOverflowSanityCheck(const size_t count, 1012 const size_t quantum) 1013 { 1014 size_t 1015 size; 1016 1017 size=count*quantum; 1018 if ((count == 0) || (quantum != (size/count))) 1019 { 1020 errno=ENOMEM; 1021 return(MagickTrue); 1022 } 1023 return(MagickFalse); 1024 } 1025 1026 /* 1028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1029 % % 1030 % % 1031 % % 1032 % R e l i n q u i s h A l i g n e d M e m o r y % 1033 % % 1034 % % 1035 % % 1036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1037 % 1038 % RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory() 1039 % or reuse. 1040 % 1041 % The format of the RelinquishAlignedMemory method is: 1042 % 1043 % void *RelinquishAlignedMemory(void *memory) 1044 % 1045 % A description of each parameter follows: 1046 % 1047 % o memory: A pointer to a block of memory to free for reuse. 1048 % 1049 */ 1050 MagickExport void *RelinquishAlignedMemory(void *memory) 1051 { 1052 if (memory == (void *) NULL) 1053 return((void *) NULL); 1054 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN) 1055 free(memory); 1056 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC) 1057 _aligned_free(memory); 1058 #else 1059 free(*((void **) memory-1)); 1060 #endif 1061 return(NULL); 1062 } 1063 1064 /* 1066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1067 % % 1068 % % 1069 % % 1070 % R e l i n q u i s h M a g i c k M e m o r y % 1071 % % 1072 % % 1073 % % 1074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1075 % 1076 % RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory() 1077 % or AcquireQuantumMemory() for reuse. 1078 % 1079 % The format of the RelinquishMagickMemory method is: 1080 % 1081 % void *RelinquishMagickMemory(void *memory) 1082 % 1083 % A description of each parameter follows: 1084 % 1085 % o memory: A pointer to a block of memory to free for reuse. 1086 % 1087 */ 1088 MagickExport void *RelinquishMagickMemory(void *memory) 1089 { 1090 if (memory == (void *) NULL) 1091 return((void *) NULL); 1092 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 1093 memory_methods.destroy_memory_handler(memory); 1094 #else 1095 LockSemaphoreInfo(memory_semaphore); 1096 assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0); 1097 assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0); 1098 if ((*BlockHeader(memory) & PreviousBlockBit) == 0) 1099 { 1100 void 1101 *previous; 1102 1103 /* 1104 Coalesce with previous adjacent block. 1105 */ 1106 previous=PreviousBlock(memory); 1107 RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous))); 1108 *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) | 1109 (*BlockHeader(previous) & ~SizeMask); 1110 memory=previous; 1111 } 1112 if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0) 1113 { 1114 void 1115 *next; 1116 1117 /* 1118 Coalesce with next adjacent block. 1119 */ 1120 next=NextBlock(memory); 1121 RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next))); 1122 *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) | 1123 (*BlockHeader(memory) & ~SizeMask); 1124 } 1125 *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory); 1126 *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit); 1127 InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory))); 1128 UnlockSemaphoreInfo(memory_semaphore); 1129 #endif 1130 return((void *) NULL); 1131 } 1132 1133 /* 1135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1136 % % 1137 % % 1138 % % 1139 % R e l i n q u i s h V i r t u a l M e m o r y % 1140 % % 1141 % % 1142 % % 1143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1144 % 1145 % RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory(). 1146 % 1147 % The format of the RelinquishVirtualMemory method is: 1148 % 1149 % MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info) 1150 % 1151 % A description of each parameter follows: 1152 % 1153 % o memory_info: A pointer to a block of memory to free for reuse. 1154 % 1155 */ 1156 MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info) 1157 { 1158 assert(memory_info != (MemoryInfo *) NULL); 1159 assert(memory_info->signature == MagickCoreSignature); 1160 if (memory_info->blob != (void *) NULL) 1161 switch (memory_info->type) 1162 { 1163 case AlignedVirtualMemory: 1164 { 1165 memory_info->blob=RelinquishAlignedMemory(memory_info->blob); 1166 break; 1167 } 1168 case MapVirtualMemory: 1169 { 1170 (void) UnmapBlob(memory_info->blob,memory_info->length); 1171 memory_info->blob=NULL; 1172 if (*memory_info->filename != '\0') 1173 (void) RelinquishUniqueFileResource(memory_info->filename); 1174 break; 1175 } 1176 case UnalignedVirtualMemory: 1177 default: 1178 { 1179 memory_info->blob=RelinquishMagickMemory(memory_info->blob); 1180 break; 1181 } 1182 } 1183 memory_info->signature=(~MagickCoreSignature); 1184 memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info); 1185 return(memory_info); 1186 } 1187 1188 /* 1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1191 % % 1192 % % 1193 % % 1194 % R e s e t M a g i c k M e m o r y % 1195 % % 1196 % % 1197 % % 1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1199 % 1200 % ResetMagickMemory() fills the first size bytes of the memory area pointed to 1201 % by memory with the constant byte c. 1202 % 1203 % The format of the ResetMagickMemory method is: 1204 % 1205 % void *ResetMagickMemory(void *memory,int byte,const size_t size) 1206 % 1207 % A description of each parameter follows: 1208 % 1209 % o memory: a pointer to a memory allocation. 1210 % 1211 % o byte: set the memory to this value. 1212 % 1213 % o size: size of the memory to reset. 1214 % 1215 */ 1216 MagickExport void *ResetMagickMemory(void *memory,int byte,const size_t size) 1217 { 1218 assert(memory != (void *) NULL); 1219 return(memset(memory,byte,size)); 1220 } 1221 1222 /* 1224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1225 % % 1226 % % 1227 % % 1228 + R e s e t M a x M e m o r y R e q u e s t % 1229 % % 1230 % % 1231 % % 1232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1233 % 1234 % ResetMaxMemoryRequest() resets the max_memory_request value. 1235 % 1236 % The format of the ResetMaxMemoryRequest method is: 1237 % 1238 % void ResetMaxMemoryRequest(void) 1239 % 1240 */ 1241 MagickPrivate void ResetMaxMemoryRequest(void) 1242 { 1243 max_memory_request=0; 1244 } 1245 1246 /* 1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1249 % % 1250 % % 1251 % % 1252 + R e s e t V i r t u a l A n o n y m o u s M e m o r y % 1253 % % 1254 % % 1255 % % 1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1257 % 1258 % ResetVirtualAnonymousMemory() resets the virtual_anonymous_memory value. 1259 % 1260 % The format of the ResetVirtualAnonymousMemory method is: 1261 % 1262 % void ResetVirtualAnonymousMemory(void) 1263 % 1264 */ 1265 MagickPrivate void ResetVirtualAnonymousMemory(void) 1266 { 1267 virtual_anonymous_memory=0; 1268 } 1269 1270 /* 1272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1273 % % 1274 % % 1275 % % 1276 % R e s i z e M a g i c k M e m o r y % 1277 % % 1278 % % 1279 % % 1280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1281 % 1282 % ResizeMagickMemory() changes the size of the memory and returns a pointer to 1283 % the (possibly moved) block. The contents will be unchanged up to the 1284 % lesser of the new and old sizes. 1285 % 1286 % The format of the ResizeMagickMemory method is: 1287 % 1288 % void *ResizeMagickMemory(void *memory,const size_t size) 1289 % 1290 % A description of each parameter follows: 1291 % 1292 % o memory: A pointer to a memory allocation. 1293 % 1294 % o size: the new size of the allocated memory. 1295 % 1296 */ 1297 1298 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 1299 static inline void *ResizeBlock(void *block,size_t size) 1300 { 1301 register void 1302 *memory; 1303 1304 if (block == (void *) NULL) 1305 return(AcquireBlock(size)); 1306 memory=AcquireBlock(size); 1307 if (memory == (void *) NULL) 1308 return((void *) NULL); 1309 if (size <= (SizeOfBlock(block)-sizeof(size_t))) 1310 (void) memcpy(memory,block,size); 1311 else 1312 (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t)); 1313 memory_pool.allocation+=size; 1314 return(memory); 1315 } 1316 #endif 1317 1318 MagickExport void *ResizeMagickMemory(void *memory,const size_t size) 1319 { 1320 register void 1321 *block; 1322 1323 if (memory == (void *) NULL) 1324 return(AcquireMagickMemory(size)); 1325 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT) 1326 block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size); 1327 if (block == (void *) NULL) 1328 memory=RelinquishMagickMemory(memory); 1329 #else 1330 LockSemaphoreInfo(memory_semaphore); 1331 block=ResizeBlock(memory,size == 0 ? 1UL : size); 1332 if (block == (void *) NULL) 1333 { 1334 if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse) 1335 { 1336 UnlockSemaphoreInfo(memory_semaphore); 1337 memory=RelinquishMagickMemory(memory); 1338 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1339 } 1340 block=ResizeBlock(memory,size == 0 ? 1UL : size); 1341 assert(block != (void *) NULL); 1342 } 1343 UnlockSemaphoreInfo(memory_semaphore); 1344 memory=RelinquishMagickMemory(memory); 1345 #endif 1346 return(block); 1347 } 1348 1349 /* 1351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1352 % % 1353 % % 1354 % % 1355 % R e s i z e Q u a n t u m M e m o r y % 1356 % % 1357 % % 1358 % % 1359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1360 % 1361 % ResizeQuantumMemory() changes the size of the memory and returns a pointer 1362 % to the (possibly moved) block. The contents will be unchanged up to the 1363 % lesser of the new and old sizes. 1364 % 1365 % The format of the ResizeQuantumMemory method is: 1366 % 1367 % void *ResizeQuantumMemory(void *memory,const size_t count, 1368 % const size_t quantum) 1369 % 1370 % A description of each parameter follows: 1371 % 1372 % o memory: A pointer to a memory allocation. 1373 % 1374 % o count: the number of quantum elements to allocate. 1375 % 1376 % o quantum: the number of bytes in each quantum. 1377 % 1378 */ 1379 MagickExport void *ResizeQuantumMemory(void *memory,const size_t count, 1380 const size_t quantum) 1381 { 1382 size_t 1383 extent; 1384 1385 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse) 1386 { 1387 memory=RelinquishMagickMemory(memory); 1388 return((void *) NULL); 1389 } 1390 extent=count*quantum; 1391 return(ResizeMagickMemory(memory,extent)); 1392 } 1393 1394 /* 1396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1397 % % 1398 % % 1399 % % 1400 % S e t M a g i c k M e m o r y M e t h o d s % 1401 % % 1402 % % 1403 % % 1404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1405 % 1406 % SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy 1407 % memory. Your custom memory methods must be set prior to the 1408 % MagickCoreGenesis() method. 1409 % 1410 % The format of the SetMagickMemoryMethods() method is: 1411 % 1412 % SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler, 1413 % ResizeMemoryHandler resize_memory_handler, 1414 % DestroyMemoryHandler destroy_memory_handler) 1415 % 1416 % A description of each parameter follows: 1417 % 1418 % o acquire_memory_handler: method to acquire memory (e.g. malloc). 1419 % 1420 % o resize_memory_handler: method to resize memory (e.g. realloc). 1421 % 1422 % o destroy_memory_handler: method to destroy memory (e.g. free). 1423 % 1424 */ 1425 MagickExport void SetMagickMemoryMethods( 1426 AcquireMemoryHandler acquire_memory_handler, 1427 ResizeMemoryHandler resize_memory_handler, 1428 DestroyMemoryHandler destroy_memory_handler) 1429 { 1430 /* 1431 Set memory methods. 1432 */ 1433 if (acquire_memory_handler != (AcquireMemoryHandler) NULL) 1434 memory_methods.acquire_memory_handler=acquire_memory_handler; 1435 if (resize_memory_handler != (ResizeMemoryHandler) NULL) 1436 memory_methods.resize_memory_handler=resize_memory_handler; 1437 if (destroy_memory_handler != (DestroyMemoryHandler) NULL) 1438 memory_methods.destroy_memory_handler=destroy_memory_handler; 1439 } 1440