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