2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % MagickCore Memory Allocation Methods %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % https://imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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
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.
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
56 #include "MagickCore/studio.h"
57 #include "MagickCore/blob.h"
58 #include "MagickCore/blob-private.h"
59 #include "MagickCore/exception.h"
60 #include "MagickCore/exception-private.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/memory-private.h"
63 #include "MagickCore/policy.h"
64 #include "MagickCore/resource_.h"
65 #include "MagickCore/semaphore.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/string-private.h"
68 #include "MagickCore/utility-private.h"
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)
96 UndefinedVirtualMemory,
99 UnalignedVirtualMemory
102 typedef struct _DataSegmentInfo
114 struct _DataSegmentInfo
119 typedef struct _MagickMemoryMethods
122 acquire_memory_handler;
125 resize_memory_handler;
128 destroy_memory_handler;
129 } MagickMemoryMethods;
134 filename[MagickPathExtent];
149 typedef struct _MemoryPool
155 *blocks[MaxBlocks+1];
161 *segments[MaxSegments],
162 segment_pool[MaxSegments];
169 max_memory_request = 0,
170 virtual_anonymous_memory = 0;
173 static void* MSCMalloc(size_t size)
177 static void* MSCRealloc(void* ptr, size_t size)
179 return realloc(ptr, size);
181 static void MSCFree(void* ptr)
187 static MagickMemoryMethods
191 (AcquireMemoryHandler) MSCMalloc,
192 (ResizeMemoryHandler) MSCRealloc,
193 (DestroyMemoryHandler) MSCFree
195 (AcquireMemoryHandler) malloc,
196 (ResizeMemoryHandler) realloc,
197 (DestroyMemoryHandler) free
200 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
205 *memory_semaphore = (SemaphoreInfo *) NULL;
207 static volatile DataSegmentInfo
208 *free_segments = (DataSegmentInfo *) NULL;
211 Forward declarations.
213 static MagickBooleanType
218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222 % A c q u i r e A l i g n e d M e m o r y %
226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228 % AcquireAlignedMemory() returns a pointer to a block of memory at least size
229 % bytes whose address is aligned on a cache line or page boundary.
231 % The format of the AcquireAlignedMemory method is:
233 % void *AcquireAlignedMemory(const size_t count,const size_t quantum)
235 % A description of each parameter follows:
237 % o count: the number of quantum elements to allocate.
239 % o quantum: the number of bytes in each quantum.
242 MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum)
244 #define AlignedExtent(size,alignment) \
245 (((size)+((alignment)-1)) & ~((alignment)-1))
246 #define AlignedPowerOf2(x) ((((x) - 1) & (x)) == 0)
256 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
257 return((void *) NULL);
260 alignment=CACHE_LINE_SIZE;
261 extent=AlignedExtent(size,alignment);
262 if ((size == 0) || (extent < size))
263 return((void *) NULL);
264 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
265 if (posix_memalign(&memory,alignment,extent) != 0)
267 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
268 memory=_aligned_malloc(extent,alignment);
274 if ((alignment == 0) || (alignment % sizeof(void *) != 0) ||
275 (AlignedPowerOf2(alignment/sizeof(void *)) == 0))
278 return((void *) NULL);
280 if (size > (SIZE_MAX-alignment-sizeof(void *)-1))
283 return((void *) NULL);
285 extent=(size+alignment-1)+sizeof(void *);
288 p=AcquireMagickMemory(extent);
291 memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment);
292 *((void **) memory-1)=p;
300 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306 + A c q u i r e B l o c k %
310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 % AcquireBlock() returns a pointer to a block of memory at least size bytes
313 % suitably aligned for any use.
315 % The format of the AcquireBlock method is:
317 % void *AcquireBlock(const size_t size)
319 % A description of each parameter follows:
321 % o size: the size of the memory in bytes to allocate.
325 static inline size_t AllocationPolicy(size_t size)
331 The linear distribution.
334 assert(size % (4*sizeof(size_t)) == 0);
335 if (size <= BlockThreshold)
336 return(size/(4*sizeof(size_t)));
338 Check for the largest block size.
340 if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L))))
341 return(MaxBlocks-1L);
343 Otherwise use a power of two distribution.
345 blocksize=BlockThreshold/(4*sizeof(size_t));
346 for ( ; size > BlockThreshold; size/=2)
348 assert(blocksize > (BlockThreshold/(4*sizeof(size_t))));
349 assert(blocksize < (MaxBlocks-1L));
353 static inline void InsertFreeBlock(void *block,const size_t i)
362 size=SizeOfBlock(block);
363 previous=(void *) NULL;
364 next=memory_pool.blocks[i];
365 while ((next != (void *) NULL) && (SizeOfBlock(next) < size))
368 next=NextBlockInList(next);
370 PreviousBlockInList(block)=previous;
371 NextBlockInList(block)=next;
372 if (previous != (void *) NULL)
373 NextBlockInList(previous)=block;
375 memory_pool.blocks[i]=block;
376 if (next != (void *) NULL)
377 PreviousBlockInList(next)=block;
380 static inline void RemoveFreeBlock(void *block,const size_t i)
386 next=NextBlockInList(block);
387 previous=PreviousBlockInList(block);
388 if (previous == (void *) NULL)
389 memory_pool.blocks[i]=next;
391 NextBlockInList(previous)=next;
392 if (next != (void *) NULL)
393 PreviousBlockInList(next)=previous;
396 static void *AcquireBlock(size_t size)
407 size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t));
408 i=AllocationPolicy(size);
409 block=memory_pool.blocks[i];
410 while ((block != (void *) NULL) && (SizeOfBlock(block) < size))
411 block=NextBlockInList(block);
412 if (block == (void *) NULL)
415 while (memory_pool.blocks[i] == (void *) NULL)
417 block=memory_pool.blocks[i];
419 return((void *) NULL);
421 assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0);
422 assert(SizeOfBlock(block) >= size);
423 RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block)));
424 if (SizeOfBlock(block) > size)
435 next=(char *) block+size;
436 blocksize=SizeOfBlock(block)-size;
437 *BlockHeader(next)=blocksize;
438 *BlockFooter(next,blocksize)=blocksize;
439 InsertFreeBlock(next,AllocationPolicy(blocksize));
440 *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask);
442 assert(size == SizeOfBlock(block));
443 *BlockHeader(NextBlock(block))|=PreviousBlockBit;
444 memory_pool.allocation+=size;
450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454 % A c q u i r e M a g i c k M e m o r y %
458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460 % AcquireMagickMemory() returns a pointer to a block of memory at least size
461 % bytes suitably aligned for any use.
463 % The format of the AcquireMagickMemory method is:
465 % void *AcquireMagickMemory(const size_t size)
467 % A description of each parameter follows:
469 % o size: the size of the memory in bytes to allocate.
472 MagickExport void *AcquireMagickMemory(const size_t size)
477 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
478 memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
480 if (memory_semaphore == (SemaphoreInfo *) NULL)
481 ActivateSemaphoreInfo(&memory_semaphore);
482 if (free_segments == (DataSegmentInfo *) NULL)
484 LockSemaphoreInfo(memory_semaphore);
485 if (free_segments == (DataSegmentInfo *) NULL)
490 assert(2*sizeof(size_t) > (size_t) (~SizeMask));
491 (void) memset(&memory_pool,0,sizeof(memory_pool));
492 memory_pool.allocation=SegmentSize;
493 memory_pool.blocks[MaxBlocks]=(void *) (-1);
494 for (i=0; i < MaxSegments; i++)
497 memory_pool.segment_pool[i].previous=
498 (&memory_pool.segment_pool[i-1]);
499 if (i != (MaxSegments-1))
500 memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]);
502 free_segments=(&memory_pool.segment_pool[0]);
504 UnlockSemaphoreInfo(memory_semaphore);
506 LockSemaphoreInfo(memory_semaphore);
507 memory=AcquireBlock(size == 0 ? 1UL : size);
508 if (memory == (void *) NULL)
510 if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse)
511 memory=AcquireBlock(size == 0 ? 1UL : size);
513 UnlockSemaphoreInfo(memory_semaphore);
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523 % A c q u i r e Q u a n t u m M e m o r y %
527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529 % AcquireQuantumMemory() returns a pointer to a block of memory at least
530 % count * quantum bytes suitably aligned for any use.
532 % The format of the AcquireQuantumMemory method is:
534 % void *AcquireQuantumMemory(const size_t count,const size_t quantum)
536 % A description of each parameter follows:
538 % o count: the number of quantum elements to allocate.
540 % o quantum: the number of bytes in each quantum.
543 MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
548 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
549 return((void *) NULL);
550 extent=count*quantum;
551 return(AcquireMagickMemory(extent));
555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
559 % A c q u i r e V i r t u a l M e m o r y %
563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 % AcquireVirtualMemory() allocates a pointer to a block of memory at least
566 % size bytes suitably aligned for any use. In addition to heap, it also
567 % supports memory-mapped and file-based memory-mapped memory requests.
569 % The format of the AcquireVirtualMemory method is:
571 % MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum)
573 % A description of each parameter follows:
575 % o count: the number of quantum elements to allocate.
577 % o quantum: the number of bytes in each quantum.
581 MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
582 const size_t quantum)
593 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
594 return((MemoryInfo *) NULL);
595 if (virtual_anonymous_memory == 0)
597 virtual_anonymous_memory=1;
598 value=GetPolicyValue("system:memory-map");
599 if (LocaleCompare(value,"anonymous") == 0)
602 The security policy sets anonymous mapping for the memory request.
604 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
605 virtual_anonymous_memory=2;
608 value=DestroyString(value);
610 memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
611 sizeof(*memory_info)));
612 if (memory_info == (MemoryInfo *) NULL)
613 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
614 (void) memset(memory_info,0,sizeof(*memory_info));
615 extent=count*quantum;
616 memory_info->length=extent;
617 memory_info->signature=MagickCoreSignature;
618 if ((virtual_anonymous_memory == 1) &&
619 ((count*quantum) <= GetMaxMemoryRequest()))
621 memory_info->blob=AcquireAlignedMemory(1,extent);
622 if (memory_info->blob != NULL)
623 memory_info->type=AlignedVirtualMemory;
625 if (memory_info->blob == NULL)
628 Acquire anonymous memory map.
630 memory_info->blob=NULL;
631 if ((count*quantum) <= GetMaxMemoryRequest())
632 memory_info->blob=MapBlob(-1,IOMode,0,extent);
633 if (memory_info->blob != NULL)
634 memory_info->type=MapVirtualMemory;
641 Anonymous memory mapping failed, try file-backed memory mapping.
643 file=AcquireUniqueFileResource(memory_info->filename);
649 offset=(MagickOffsetType) lseek(file,extent-1,SEEK_SET);
650 if ((offset == (MagickOffsetType) (extent-1)) &&
651 (write(file,"",1) == 1))
653 #if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
654 memory_info->blob=MapBlob(file,IOMode,0,extent);
656 if (posix_fallocate(file,0,extent) == 0)
657 memory_info->blob=MapBlob(file,IOMode,0,extent);
659 if (memory_info->blob != NULL)
660 memory_info->type=MapVirtualMemory;
663 (void) RelinquishUniqueFileResource(
664 memory_info->filename);
665 *memory_info->filename='\0';
672 if (memory_info->blob == NULL)
674 memory_info->blob=AcquireQuantumMemory(1,extent);
675 if (memory_info->blob != NULL)
676 memory_info->type=UnalignedVirtualMemory;
678 if (memory_info->blob == NULL)
679 memory_info=RelinquishVirtualMemory(memory_info);
684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688 % C o p y M a g i c k M e m o r y %
692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
694 % CopyMagickMemory() copies size bytes from memory area source to the
695 % destination. Copying between objects that overlap will take place
696 % correctly. It returns destination.
698 % The format of the CopyMagickMemory method is:
700 % void *CopyMagickMemory(void *destination,const void *source,
703 % A description of each parameter follows:
705 % o destination: the destination.
707 % o source: the source.
709 % o size: the size of the memory in bytes to allocate.
712 MagickExport void *CopyMagickMemory(void *destination,const void *source,
715 register const unsigned char
718 register unsigned char
721 assert(destination != (void *) NULL);
722 assert(source != (const void *) NULL);
723 p=(const unsigned char *) source;
724 q=(unsigned char *) destination;
725 if (((q+size) < p) || (q > (p+size)))
728 default: return(memcpy(destination,source,size));
737 case 0: return(destination);
739 return(memmove(destination,source,size));
743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 + D e s t r o y M a g i c k M e m o r y %
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753 % DestroyMagickMemory() deallocates memory associated with the memory manager.
755 % The format of the DestroyMagickMemory method is:
757 % DestroyMagickMemory(void)
760 MagickExport void DestroyMagickMemory(void)
762 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
766 if (memory_semaphore == (SemaphoreInfo *) NULL)
767 ActivateSemaphoreInfo(&memory_semaphore);
768 LockSemaphoreInfo(memory_semaphore);
769 for (i=0; i < (ssize_t) memory_pool.number_segments; i++)
770 if (memory_pool.segments[i]->mapped == MagickFalse)
771 memory_methods.destroy_memory_handler(
772 memory_pool.segments[i]->allocation);
774 (void) UnmapBlob(memory_pool.segments[i]->allocation,
775 memory_pool.segments[i]->length);
776 free_segments=(DataSegmentInfo *) NULL;
777 (void) memset(&memory_pool,0,sizeof(memory_pool));
778 UnlockSemaphoreInfo(memory_semaphore);
779 RelinquishSemaphoreInfo(&memory_semaphore);
783 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 + E x p a n d H e a p %
793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 % ExpandHeap() get more memory from the system. It returns MagickTrue on
796 % success otherwise MagickFalse.
798 % The format of the ExpandHeap method is:
800 % MagickBooleanType ExpandHeap(size_t size)
802 % A description of each parameter follows:
804 % o size: the size of the memory in bytes we require.
807 static MagickBooleanType ExpandHeap(size_t size)
827 blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
828 assert(memory_pool.number_segments < MaxSegments);
829 segment=MapBlob(-1,IOMode,0,blocksize);
830 mapped=segment != (void *) NULL ? MagickTrue : MagickFalse;
831 if (segment == (void *) NULL)
832 segment=(void *) memory_methods.acquire_memory_handler(blocksize);
833 if (segment == (void *) NULL)
835 segment_info=(DataSegmentInfo *) free_segments;
836 free_segments=segment_info->next;
837 segment_info->mapped=mapped;
838 segment_info->length=blocksize;
839 segment_info->allocation=segment;
840 segment_info->bound=(char *) segment+blocksize;
841 i=(ssize_t) memory_pool.number_segments-1;
842 for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--)
843 memory_pool.segments[i+1]=memory_pool.segments[i];
844 memory_pool.segments[i+1]=segment_info;
845 memory_pool.number_segments++;
846 size=blocksize-12*sizeof(size_t);
847 block=(char *) segment_info->allocation+4*sizeof(size_t);
848 *BlockHeader(block)=size | PreviousBlockBit;
849 *BlockFooter(block,size)=size;
850 InsertFreeBlock(block,AllocationPolicy(size));
851 block=NextBlock(block);
852 assert(block < segment_info->bound);
853 *BlockHeader(block)=2*sizeof(size_t);
854 *BlockHeader(NextBlock(block))=PreviousBlockBit;
860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 % G e t M a g i c k M e m o r y M e t h o d s %
868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
870 % GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy
873 % The format of the GetMagickMemoryMethods() method is:
875 % void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler,
876 % ResizeMemoryHandler *resize_memory_handler,
877 % DestroyMemoryHandler *destroy_memory_handler)
879 % A description of each parameter follows:
881 % o acquire_memory_handler: method to acquire memory (e.g. malloc).
883 % o resize_memory_handler: method to resize memory (e.g. realloc).
885 % o destroy_memory_handler: method to destroy memory (e.g. free).
888 MagickExport void GetMagickMemoryMethods(
889 AcquireMemoryHandler *acquire_memory_handler,
890 ResizeMemoryHandler *resize_memory_handler,
891 DestroyMemoryHandler *destroy_memory_handler)
893 assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL);
894 assert(resize_memory_handler != (ResizeMemoryHandler *) NULL);
895 assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL);
896 *acquire_memory_handler=memory_methods.acquire_memory_handler;
897 *resize_memory_handler=memory_methods.resize_memory_handler;
898 *destroy_memory_handler=memory_methods.destroy_memory_handler;
902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
906 + G e t M a x M e m o r y R e q u e s t %
910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
912 % GetMaxMemoryRequest() returns the max_memory_request value.
914 % The format of the GetMaxMemoryRequest method is:
916 % size_t GetMaxMemoryRequest(void)
919 MagickExport size_t GetMaxMemoryRequest(void)
921 if (max_memory_request == 0)
926 value=GetPolicyValue("system:max-memory-request");
927 if (value != (char *) NULL)
930 The security policy sets a max memory request limit.
932 max_memory_request=StringToSizeType(value,100.0);
933 value=DestroyString(value);
936 max_memory_request=(size_t) MagickULLConstant(~0);
938 return(max_memory_request);
942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
946 % G e t V i r t u a l M e m o r y B l o b %
950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
952 % GetVirtualMemoryBlob() returns the virtual memory blob associated with the
953 % specified MemoryInfo structure.
955 % The format of the GetVirtualMemoryBlob method is:
957 % void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
959 % A description of each parameter follows:
961 % o memory_info: The MemoryInfo structure.
963 MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
965 assert(memory_info != (const MemoryInfo *) NULL);
966 assert(memory_info->signature == MagickCoreSignature);
967 return(memory_info->blob);
971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 + H e a p O v e r f l o w S a n i t y C h e c k %
979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
981 % HeapOverflowSanityCheck() returns MagickTrue if the heap allocation request
982 % does not exceed the maximum limits of a size_t otherwise MagickFalse.
984 % The format of the HeapOverflowSanityCheck method is:
986 % MagickBooleanType HeapOverflowSanityCheck(const size_t count,
987 % const size_t quantum)
989 % A description of each parameter follows:
991 % o size: the size of the memory in bytes we require.
994 MagickExport MagickBooleanType HeapOverflowSanityCheck(const size_t count,
995 const size_t quantum)
1001 if ((count == 0) || (quantum != (size/count)))
1006 return(MagickFalse);
1010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014 % R e l i n q u i s h A l i g n e d M e m o r y %
1018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020 % RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory()
1023 % The format of the RelinquishAlignedMemory method is:
1025 % void *RelinquishAlignedMemory(void *memory)
1027 % A description of each parameter follows:
1029 % o memory: A pointer to a block of memory to free for reuse.
1032 MagickExport void *RelinquishAlignedMemory(void *memory)
1034 if (memory == (void *) NULL)
1035 return((void *) NULL);
1036 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
1038 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
1039 _aligned_free(memory);
1041 RelinquishMagickMemory(*((void **) memory-1));
1047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1051 % R e l i n q u i s h M a g i c k M e m o r y %
1055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057 % RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory()
1058 % or AcquireQuantumMemory() for reuse.
1060 % The format of the RelinquishMagickMemory method is:
1062 % void *RelinquishMagickMemory(void *memory)
1064 % A description of each parameter follows:
1066 % o memory: A pointer to a block of memory to free for reuse.
1069 MagickExport void *RelinquishMagickMemory(void *memory)
1071 if (memory == (void *) NULL)
1072 return((void *) NULL);
1073 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1074 memory_methods.destroy_memory_handler(memory);
1076 LockSemaphoreInfo(memory_semaphore);
1077 assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0);
1078 assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0);
1079 if ((*BlockHeader(memory) & PreviousBlockBit) == 0)
1085 Coalesce with previous adjacent block.
1087 previous=PreviousBlock(memory);
1088 RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous)));
1089 *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) |
1090 (*BlockHeader(previous) & ~SizeMask);
1093 if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0)
1099 Coalesce with next adjacent block.
1101 next=NextBlock(memory);
1102 RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next)));
1103 *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) |
1104 (*BlockHeader(memory) & ~SizeMask);
1106 *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory);
1107 *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit);
1108 InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory)));
1109 UnlockSemaphoreInfo(memory_semaphore);
1111 return((void *) NULL);
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 % R e l i n q u i s h V i r t u a l M e m o r y %
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125 % RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory().
1127 % The format of the RelinquishVirtualMemory method is:
1129 % MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1131 % A description of each parameter follows:
1133 % o memory_info: A pointer to a block of memory to free for reuse.
1136 MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1138 assert(memory_info != (MemoryInfo *) NULL);
1139 assert(memory_info->signature == MagickCoreSignature);
1140 if (memory_info->blob != (void *) NULL)
1141 switch (memory_info->type)
1143 case AlignedVirtualMemory:
1145 memory_info->blob=RelinquishAlignedMemory(memory_info->blob);
1148 case MapVirtualMemory:
1150 (void) UnmapBlob(memory_info->blob,memory_info->length);
1151 memory_info->blob=NULL;
1152 if (*memory_info->filename != '\0')
1153 (void) RelinquishUniqueFileResource(memory_info->filename);
1156 case UnalignedVirtualMemory:
1159 memory_info->blob=RelinquishMagickMemory(memory_info->blob);
1163 memory_info->signature=(~MagickCoreSignature);
1164 memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info);
1165 return(memory_info);
1169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 % R e s e t M a g i c k M e m o r y %
1177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179 % ResetMagickMemory() fills the first size bytes of the memory area pointed to
1180 % by memory with the constant byte c.
1182 % The format of the ResetMagickMemory method is:
1184 % void *ResetMagickMemory(void *memory,int byte,const size_t size)
1186 % A description of each parameter follows:
1188 % o memory: a pointer to a memory allocation.
1190 % o byte: set the memory to this value.
1192 % o size: size of the memory to reset.
1195 MagickExport void *ResetMagickMemory(void *memory,int byte,const size_t size)
1197 assert(memory != (void *) NULL);
1198 return(memset(memory,byte,size));
1202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206 + R e s e t M a x M e m o r y R e q u e s t %
1210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 % ResetMaxMemoryRequest() resets the max_memory_request value.
1214 % The format of the ResetMaxMemoryRequest method is:
1216 % void ResetMaxMemoryRequest(void)
1219 MagickPrivate void ResetMaxMemoryRequest(void)
1221 max_memory_request=0;
1225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1229 + 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 %
1233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1235 % ResetVirtualAnonymousMemory() resets the virtual_anonymous_memory value.
1237 % The format of the ResetVirtualAnonymousMemory method is:
1239 % void ResetVirtualAnonymousMemory(void)
1242 MagickPrivate void ResetVirtualAnonymousMemory(void)
1244 virtual_anonymous_memory=0;
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 % R e s i z e M a g i c k M e m o r y %
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258 % ResizeMagickMemory() changes the size of the memory and returns a pointer to
1259 % the (possibly moved) block. The contents will be unchanged up to the
1260 % lesser of the new and old sizes.
1262 % The format of the ResizeMagickMemory method is:
1264 % void *ResizeMagickMemory(void *memory,const size_t size)
1266 % A description of each parameter follows:
1268 % o memory: A pointer to a memory allocation.
1270 % o size: the new size of the allocated memory.
1274 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1275 static inline void *ResizeBlock(void *block,size_t size)
1280 if (block == (void *) NULL)
1281 return(AcquireBlock(size));
1282 memory=AcquireBlock(size);
1283 if (memory == (void *) NULL)
1284 return((void *) NULL);
1285 if (size <= (SizeOfBlock(block)-sizeof(size_t)))
1286 (void) memcpy(memory,block,size);
1288 (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
1289 memory_pool.allocation+=size;
1294 MagickExport void *ResizeMagickMemory(void *memory,const size_t size)
1299 if (memory == (void *) NULL)
1300 return(AcquireMagickMemory(size));
1301 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1302 block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
1303 if (block == (void *) NULL)
1304 memory=RelinquishMagickMemory(memory);
1306 LockSemaphoreInfo(memory_semaphore);
1307 block=ResizeBlock(memory,size == 0 ? 1UL : size);
1308 if (block == (void *) NULL)
1310 if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
1312 UnlockSemaphoreInfo(memory_semaphore);
1313 memory=RelinquishMagickMemory(memory);
1314 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1316 block=ResizeBlock(memory,size == 0 ? 1UL : size);
1317 assert(block != (void *) NULL);
1319 UnlockSemaphoreInfo(memory_semaphore);
1320 memory=RelinquishMagickMemory(memory);
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 % R e s i z e Q u a n t u m M e m o r y %
1334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1336 % ResizeQuantumMemory() changes the size of the memory and returns a pointer
1337 % to the (possibly moved) block. The contents will be unchanged up to the
1338 % lesser of the new and old sizes.
1340 % The format of the ResizeQuantumMemory method is:
1342 % void *ResizeQuantumMemory(void *memory,const size_t count,
1343 % const size_t quantum)
1345 % A description of each parameter follows:
1347 % o memory: A pointer to a memory allocation.
1349 % o count: the number of quantum elements to allocate.
1351 % o quantum: the number of bytes in each quantum.
1354 MagickExport void *ResizeQuantumMemory(void *memory,const size_t count,
1355 const size_t quantum)
1360 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
1362 memory=RelinquishMagickMemory(memory);
1363 return((void *) NULL);
1365 extent=count*quantum;
1366 return(ResizeMagickMemory(memory,extent));
1370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1374 % S e t M a g i c k M e m o r y M e t h o d s %
1378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380 % SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy
1381 % memory. Your custom memory methods must be set prior to the
1382 % MagickCoreGenesis() method.
1384 % The format of the SetMagickMemoryMethods() method is:
1386 % SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler,
1387 % ResizeMemoryHandler resize_memory_handler,
1388 % DestroyMemoryHandler destroy_memory_handler)
1390 % A description of each parameter follows:
1392 % o acquire_memory_handler: method to acquire memory (e.g. malloc).
1394 % o resize_memory_handler: method to resize memory (e.g. realloc).
1396 % o destroy_memory_handler: method to destroy memory (e.g. free).
1399 MagickExport void SetMagickMemoryMethods(
1400 AcquireMemoryHandler acquire_memory_handler,
1401 ResizeMemoryHandler resize_memory_handler,
1402 DestroyMemoryHandler destroy_memory_handler)
1407 if (acquire_memory_handler != (AcquireMemoryHandler) NULL)
1408 memory_methods.acquire_memory_handler=acquire_memory_handler;
1409 if (resize_memory_handler != (ResizeMemoryHandler) NULL)
1410 memory_methods.resize_memory_handler=resize_memory_handler;
1411 if (destroy_memory_handler != (DestroyMemoryHandler) NULL)
1412 memory_methods.destroy_memory_handler=destroy_memory_handler;