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-2017 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://www.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/utility-private.h"
72 #define BlockFooter(block,size) \
73 ((size_t *) ((char *) (block)+(size)-2*sizeof(size_t)))
74 #define BlockHeader(block) ((size_t *) (block)-1)
75 #define BlockSize 4096
76 #define BlockThreshold 1024
77 #define MaxBlockExponent 16
78 #define MaxBlocks ((BlockThreshold/(4*sizeof(size_t)))+MaxBlockExponent+1)
79 #define MaxSegments 1024
80 #define MemoryGuard ((0xdeadbeef << 31)+0xdeafdeed)
81 #define NextBlock(block) ((char *) (block)+SizeOfBlock(block))
82 #define NextBlockInList(block) (*(void **) (block))
83 #define PreviousBlock(block) ((char *) (block)-(*((size_t *) (block)-2)))
84 #define PreviousBlockBit 0x01
85 #define PreviousBlockInList(block) (*((void **) (block)+1))
86 #define SegmentSize (2*1024*1024)
87 #define SizeMask (~0x01)
88 #define SizeOfBlock(block) (*BlockHeader(block) & SizeMask)
95 UndefinedVirtualMemory,
98 UnalignedVirtualMemory
101 typedef struct _DataSegmentInfo
113 struct _DataSegmentInfo
118 typedef struct _MagickMemoryMethods
121 acquire_memory_handler;
124 resize_memory_handler;
127 destroy_memory_handler;
128 } MagickMemoryMethods;
133 filename[MagickPathExtent];
148 typedef struct _MemoryPool
154 *blocks[MaxBlocks+1];
160 *segments[MaxSegments],
161 segment_pool[MaxSegments];
168 static void* MSCMalloc(size_t size)
172 static void* MSCRealloc(void* ptr, size_t size)
174 return realloc(ptr, size);
176 static void MSCFree(void* ptr)
182 static MagickMemoryMethods
186 (AcquireMemoryHandler) MSCMalloc,
187 (ResizeMemoryHandler) MSCRealloc,
188 (DestroyMemoryHandler) MSCFree
190 (AcquireMemoryHandler) malloc,
191 (ResizeMemoryHandler) realloc,
192 (DestroyMemoryHandler) free
195 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
200 *memory_semaphore = (SemaphoreInfo *) NULL;
202 static volatile DataSegmentInfo
203 *free_segments = (DataSegmentInfo *) NULL;
206 Forward declarations.
208 static MagickBooleanType
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 % A c q u i r e A l i g n e d M e m o r y %
221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 % AcquireAlignedMemory() returns a pointer to a block of memory at least size
224 % bytes whose address is aligned on a cache line or page boundary.
226 % The format of the AcquireAlignedMemory method is:
228 % void *AcquireAlignedMemory(const size_t count,const size_t quantum)
230 % A description of each parameter follows:
232 % o count: the number of quantum elements to allocate.
234 % o quantum: the number of bytes in each quantum.
237 MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum)
239 #define AlignedExtent(size,alignment) \
240 (((size)+((alignment)-1)) & ~((alignment)-1))
250 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
251 return((void *) NULL);
254 alignment=CACHE_LINE_SIZE;
255 if (size > (size_t) (GetMagickPageSize() >> 1))
256 alignment=(size_t) GetMagickPageSize();
257 extent=AlignedExtent(size,CACHE_LINE_SIZE);
258 if ((size == 0) || (extent < size))
259 return((void *) NULL);
260 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
261 if (posix_memalign(&memory,alignment,extent) != 0)
263 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
264 memory=_aligned_malloc(extent,alignment);
270 extent=(size+alignment-1)+sizeof(void *);
276 memory=(void *) AlignedExtent((size_t) p+sizeof(void *),alignment);
277 *((void **) memory-1)=p;
285 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291 + A c q u i r e B l o c k %
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
297 % AcquireBlock() returns a pointer to a block of memory at least size bytes
298 % suitably aligned for any use.
300 % The format of the AcquireBlock method is:
302 % void *AcquireBlock(const size_t size)
304 % A description of each parameter follows:
306 % o size: the size of the memory in bytes to allocate.
310 static inline size_t AllocationPolicy(size_t size)
316 The linear distribution.
319 assert(size % (4*sizeof(size_t)) == 0);
320 if (size <= BlockThreshold)
321 return(size/(4*sizeof(size_t)));
323 Check for the largest block size.
325 if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L))))
326 return(MaxBlocks-1L);
328 Otherwise use a power of two distribution.
330 blocksize=BlockThreshold/(4*sizeof(size_t));
331 for ( ; size > BlockThreshold; size/=2)
333 assert(blocksize > (BlockThreshold/(4*sizeof(size_t))));
334 assert(blocksize < (MaxBlocks-1L));
338 static inline void InsertFreeBlock(void *block,const size_t i)
347 size=SizeOfBlock(block);
348 previous=(void *) NULL;
349 next=memory_pool.blocks[i];
350 while ((next != (void *) NULL) && (SizeOfBlock(next) < size))
353 next=NextBlockInList(next);
355 PreviousBlockInList(block)=previous;
356 NextBlockInList(block)=next;
357 if (previous != (void *) NULL)
358 NextBlockInList(previous)=block;
360 memory_pool.blocks[i]=block;
361 if (next != (void *) NULL)
362 PreviousBlockInList(next)=block;
365 static inline void RemoveFreeBlock(void *block,const size_t i)
371 next=NextBlockInList(block);
372 previous=PreviousBlockInList(block);
373 if (previous == (void *) NULL)
374 memory_pool.blocks[i]=next;
376 NextBlockInList(previous)=next;
377 if (next != (void *) NULL)
378 PreviousBlockInList(next)=previous;
381 static void *AcquireBlock(size_t size)
392 size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t));
393 i=AllocationPolicy(size);
394 block=memory_pool.blocks[i];
395 while ((block != (void *) NULL) && (SizeOfBlock(block) < size))
396 block=NextBlockInList(block);
397 if (block == (void *) NULL)
400 while (memory_pool.blocks[i] == (void *) NULL)
402 block=memory_pool.blocks[i];
404 return((void *) NULL);
406 assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0);
407 assert(SizeOfBlock(block) >= size);
408 RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block)));
409 if (SizeOfBlock(block) > size)
420 next=(char *) block+size;
421 blocksize=SizeOfBlock(block)-size;
422 *BlockHeader(next)=blocksize;
423 *BlockFooter(next,blocksize)=blocksize;
424 InsertFreeBlock(next,AllocationPolicy(blocksize));
425 *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask);
427 assert(size == SizeOfBlock(block));
428 *BlockHeader(NextBlock(block))|=PreviousBlockBit;
429 memory_pool.allocation+=size;
435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 % A c q u i r e M a g i c k M e m o r y %
443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445 % AcquireMagickMemory() returns a pointer to a block of memory at least size
446 % bytes suitably aligned for any use.
448 % The format of the AcquireMagickMemory method is:
450 % void *AcquireMagickMemory(const size_t size)
452 % A description of each parameter follows:
454 % o size: the size of the memory in bytes to allocate.
457 MagickExport void *AcquireMagickMemory(const size_t size)
462 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
463 memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
465 if (memory_semaphore == (SemaphoreInfo *) NULL)
466 ActivateSemaphoreInfo(&memory_semaphore);
467 if (free_segments == (DataSegmentInfo *) NULL)
469 LockSemaphoreInfo(memory_semaphore);
470 if (free_segments == (DataSegmentInfo *) NULL)
475 assert(2*sizeof(size_t) > (size_t) (~SizeMask));
476 (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool));
477 memory_pool.allocation=SegmentSize;
478 memory_pool.blocks[MaxBlocks]=(void *) (-1);
479 for (i=0; i < MaxSegments; i++)
482 memory_pool.segment_pool[i].previous=
483 (&memory_pool.segment_pool[i-1]);
484 if (i != (MaxSegments-1))
485 memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]);
487 free_segments=(&memory_pool.segment_pool[0]);
489 UnlockSemaphoreInfo(memory_semaphore);
491 LockSemaphoreInfo(memory_semaphore);
492 memory=AcquireBlock(size == 0 ? 1UL : size);
493 if (memory == (void *) NULL)
495 if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse)
496 memory=AcquireBlock(size == 0 ? 1UL : size);
498 UnlockSemaphoreInfo(memory_semaphore);
504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508 % A c q u i r e Q u a n t u m M e m o r y %
512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514 % AcquireQuantumMemory() returns a pointer to a block of memory at least
515 % count * quantum bytes suitably aligned for any use.
517 % The format of the AcquireQuantumMemory method is:
519 % void *AcquireQuantumMemory(const size_t count,const size_t quantum)
521 % A description of each parameter follows:
523 % o count: the number of quantum elements to allocate.
525 % o quantum: the number of bytes in each quantum.
528 MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
533 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
534 return((void *) NULL);
535 extent=count*quantum;
536 return(AcquireMagickMemory(extent));
540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
544 % A c q u i r e V i r t u a l M e m o r y %
548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
550 % AcquireVirtualMemory() allocates a pointer to a block of memory at least size
551 % bytes suitably aligned for any use.
553 % The format of the AcquireVirtualMemory method is:
555 % MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum)
557 % A description of each parameter follows:
559 % o count: the number of quantum elements to allocate.
561 % o quantum: the number of bytes in each quantum.
564 MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
565 const size_t quantum)
574 virtual_anonymous_memory = (-1);
576 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
577 return((MemoryInfo *) NULL);
578 memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
579 sizeof(*memory_info)));
580 if (memory_info == (MemoryInfo *) NULL)
581 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
582 (void) ResetMagickMemory(memory_info,0,sizeof(*memory_info));
583 extent=count*quantum;
584 memory_info->length=extent;
585 memory_info->signature=MagickCoreSignature;
586 if (virtual_anonymous_memory < 0)
592 Does the security policy require anonymous mapping for pixel cache?
594 virtual_anonymous_memory=0;
595 value=GetPolicyValue("system:memory-map");
596 if (LocaleCompare(value,"anonymous") == 0)
598 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
599 virtual_anonymous_memory=1;
602 value=DestroyString(value);
604 if (virtual_anonymous_memory <= 0)
606 if (AcquireMagickResource(MemoryResource,extent) != MagickFalse)
608 memory_info->blob=AcquireAlignedMemory(1,extent);
609 if (memory_info->blob != NULL)
611 memory_info->type=AlignedVirtualMemory;
615 RelinquishMagickResource(MemoryResource,extent);
619 if (AcquireMagickResource(MapResource,extent) != MagickFalse)
622 Acquire anonymous memory map.
624 memory_info->blob=MapBlob(-1,IOMode,0,extent);
625 if (memory_info->blob != NULL)
627 memory_info->type=MapVirtualMemory;
630 if (AcquireMagickResource(DiskResource,extent) != MagickFalse)
636 Anonymous memory mapping failed, try file-backed memory mapping.
637 If the MapResource request failed, there is no point in trying
638 file-backed memory mapping.
640 file=AcquireUniqueFileResource(memory_info->filename);
646 offset=(MagickOffsetType) lseek(file,extent-1,SEEK_SET);
647 if ((offset == (MagickOffsetType) (extent-1)) &&
648 (write(file,"",1) == 1))
650 memory_info->blob=MapBlob(file,IOMode,0,extent);
651 if (memory_info->blob != NULL)
654 memory_info->type=MapVirtualMemory;
659 File-backed memory mapping fail, delete the temporary file.
662 (void) RelinquishUniqueFileResource(memory_info->filename);
663 *memory_info->filename = '\0';
666 RelinquishMagickResource(DiskResource,extent);
668 RelinquishMagickResource(MapResource,extent);
670 if (memory_info->blob == NULL)
672 memory_info->blob=AcquireMagickMemory(extent);
673 if (memory_info->blob != NULL)
674 memory_info->type=UnalignedVirtualMemory;
676 if (memory_info->blob == NULL)
677 memory_info=RelinquishVirtualMemory(memory_info);
682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 % C o p y M a g i c k M e m o r y %
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692 % CopyMagickMemory() copies size bytes from memory area source to the
693 % destination. Copying between objects that overlap will take place
694 % correctly. It returns destination.
696 % The format of the CopyMagickMemory method is:
698 % void *CopyMagickMemory(void *destination,const void *source,
701 % A description of each parameter follows:
703 % o destination: the destination.
705 % o source: the source.
707 % o size: the size of the memory in bytes to allocate.
710 MagickExport void *CopyMagickMemory(void *destination,const void *source,
713 register const unsigned char
716 register unsigned char
719 assert(destination != (void *) NULL);
720 assert(source != (const void *) NULL);
721 p=(const unsigned char *) source;
722 q=(unsigned char *) destination;
723 if (((q+size) < p) || (q > (p+size)))
726 default: return(memcpy(destination,source,size));
735 case 0: return(destination);
737 return(memmove(destination,source,size));
741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
745 + D e s t r o y M a g i c k M e m o r y %
749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
751 % DestroyMagickMemory() deallocates memory associated with the memory manager.
753 % The format of the DestroyMagickMemory method is:
755 % DestroyMagickMemory(void)
758 MagickExport void DestroyMagickMemory(void)
760 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
764 if (memory_semaphore == (SemaphoreInfo *) NULL)
765 ActivateSemaphoreInfo(&memory_semaphore);
766 LockSemaphoreInfo(memory_semaphore);
767 for (i=0; i < (ssize_t) memory_pool.number_segments; i++)
768 if (memory_pool.segments[i]->mapped == MagickFalse)
769 memory_methods.destroy_memory_handler(
770 memory_pool.segments[i]->allocation);
772 (void) UnmapBlob(memory_pool.segments[i]->allocation,
773 memory_pool.segments[i]->length);
774 free_segments=(DataSegmentInfo *) NULL;
775 (void) ResetMagickMemory(&memory_pool,0,sizeof(memory_pool));
776 UnlockSemaphoreInfo(memory_semaphore);
777 RelinquishSemaphoreInfo(&memory_semaphore);
781 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787 + E x p a n d H e a p %
791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793 % ExpandHeap() get more memory from the system. It returns MagickTrue on
794 % success otherwise MagickFalse.
796 % The format of the ExpandHeap method is:
798 % MagickBooleanType ExpandHeap(size_t size)
800 % A description of each parameter follows:
802 % o size: the size of the memory in bytes we require.
805 static MagickBooleanType ExpandHeap(size_t size)
825 blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
826 assert(memory_pool.number_segments < MaxSegments);
827 segment=MapBlob(-1,IOMode,0,blocksize);
828 mapped=segment != (void *) NULL ? MagickTrue : MagickFalse;
829 if (segment == (void *) NULL)
830 segment=(void *) memory_methods.acquire_memory_handler(blocksize);
831 if (segment == (void *) NULL)
833 segment_info=(DataSegmentInfo *) free_segments;
834 free_segments=segment_info->next;
835 segment_info->mapped=mapped;
836 segment_info->length=blocksize;
837 segment_info->allocation=segment;
838 segment_info->bound=(char *) segment+blocksize;
839 i=(ssize_t) memory_pool.number_segments-1;
840 for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--)
841 memory_pool.segments[i+1]=memory_pool.segments[i];
842 memory_pool.segments[i+1]=segment_info;
843 memory_pool.number_segments++;
844 size=blocksize-12*sizeof(size_t);
845 block=(char *) segment_info->allocation+4*sizeof(size_t);
846 *BlockHeader(block)=size | PreviousBlockBit;
847 *BlockFooter(block,size)=size;
848 InsertFreeBlock(block,AllocationPolicy(size));
849 block=NextBlock(block);
850 assert(block < segment_info->bound);
851 *BlockHeader(block)=2*sizeof(size_t);
852 *BlockHeader(NextBlock(block))=PreviousBlockBit;
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
862 % G e t M a g i c k M e m o r y M e t h o d s %
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 % GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy
871 % The format of the GetMagickMemoryMethods() method is:
873 % void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler,
874 % ResizeMemoryHandler *resize_memory_handler,
875 % DestroyMemoryHandler *destroy_memory_handler)
877 % A description of each parameter follows:
879 % o acquire_memory_handler: method to acquire memory (e.g. malloc).
881 % o resize_memory_handler: method to resize memory (e.g. realloc).
883 % o destroy_memory_handler: method to destroy memory (e.g. free).
886 MagickExport void GetMagickMemoryMethods(
887 AcquireMemoryHandler *acquire_memory_handler,
888 ResizeMemoryHandler *resize_memory_handler,
889 DestroyMemoryHandler *destroy_memory_handler)
891 assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL);
892 assert(resize_memory_handler != (ResizeMemoryHandler *) NULL);
893 assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL);
894 *acquire_memory_handler=memory_methods.acquire_memory_handler;
895 *resize_memory_handler=memory_methods.resize_memory_handler;
896 *destroy_memory_handler=memory_methods.destroy_memory_handler;
900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
904 % G e t V i r t u a l M e m o r y B l o b %
908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910 % GetVirtualMemoryBlob() returns the virtual memory blob associated with the
911 % specified MemoryInfo structure.
913 % The format of the GetVirtualMemoryBlob method is:
915 % void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
917 % A description of each parameter follows:
919 % o memory_info: The MemoryInfo structure.
921 MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
923 assert(memory_info != (const MemoryInfo *) NULL);
924 assert(memory_info->signature == MagickCoreSignature);
925 return(memory_info->blob);
929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933 + H e a p O v e r f l o w S a n i t y C h e c k %
937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939 % HeapOverflowSanityCheck() returns MagickTrue if the heap allocation request
940 % does not exceed the maximum limits of a size_t otherwise MagickFalse.
942 % The format of the HeapOverflowSanityCheck method is:
944 % MagickBooleanType HeapOverflowSanityCheck(const size_t count,
945 % const size_t quantum)
947 % A description of each parameter follows:
949 % o size: the size of the memory in bytes we require.
952 MagickExport MagickBooleanType HeapOverflowSanityCheck(const size_t count,
953 const size_t quantum)
959 if ((count == 0) || (quantum != (size/count)))
968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972 % R e l i n q u i s h A l i g n e d M e m o r y %
976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978 % RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory()
981 % The format of the RelinquishAlignedMemory method is:
983 % void *RelinquishAlignedMemory(void *memory)
985 % A description of each parameter follows:
987 % o memory: A pointer to a block of memory to free for reuse.
990 MagickExport void *RelinquishAlignedMemory(void *memory)
992 if (memory == (void *) NULL)
993 return((void *) NULL);
994 #if defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
996 #elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
997 _aligned_free(memory);
999 free(*((void **) memory-1));
1005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009 % R e l i n q u i s h M a g i c k M e m o r y %
1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015 % RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory()
1016 % or AcquireQuantumMemory() for reuse.
1018 % The format of the RelinquishMagickMemory method is:
1020 % void *RelinquishMagickMemory(void *memory)
1022 % A description of each parameter follows:
1024 % o memory: A pointer to a block of memory to free for reuse.
1027 MagickExport void *RelinquishMagickMemory(void *memory)
1029 if (memory == (void *) NULL)
1030 return((void *) NULL);
1031 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1032 memory_methods.destroy_memory_handler(memory);
1034 LockSemaphoreInfo(memory_semaphore);
1035 assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0);
1036 assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0);
1037 if ((*BlockHeader(memory) & PreviousBlockBit) == 0)
1043 Coalesce with previous adjacent block.
1045 previous=PreviousBlock(memory);
1046 RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous)));
1047 *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) |
1048 (*BlockHeader(previous) & ~SizeMask);
1051 if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0)
1057 Coalesce with next adjacent block.
1059 next=NextBlock(memory);
1060 RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next)));
1061 *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) |
1062 (*BlockHeader(memory) & ~SizeMask);
1064 *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory);
1065 *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit);
1066 InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory)));
1067 UnlockSemaphoreInfo(memory_semaphore);
1069 return((void *) NULL);
1073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1077 % R e l i n q u i s h V i r t u a l M e m o r y %
1081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083 % RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory().
1085 % The format of the RelinquishVirtualMemory method is:
1087 % MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1089 % A description of each parameter follows:
1091 % o memory_info: A pointer to a block of memory to free for reuse.
1094 MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1096 assert(memory_info != (MemoryInfo *) NULL);
1097 assert(memory_info->signature == MagickCoreSignature);
1098 if (memory_info->blob != (void *) NULL)
1099 switch (memory_info->type)
1101 case AlignedVirtualMemory:
1103 memory_info->blob=RelinquishAlignedMemory(memory_info->blob);
1104 RelinquishMagickResource(MemoryResource,memory_info->length);
1107 case MapVirtualMemory:
1109 (void) UnmapBlob(memory_info->blob,memory_info->length);
1110 memory_info->blob=NULL;
1111 RelinquishMagickResource(MapResource,memory_info->length);
1112 if (*memory_info->filename != '\0')
1114 (void) RelinquishUniqueFileResource(memory_info->filename);
1115 RelinquishMagickResource(DiskResource,memory_info->length);
1119 case UnalignedVirtualMemory:
1122 memory_info->blob=RelinquishMagickMemory(memory_info->blob);
1126 memory_info->signature=(~MagickCoreSignature);
1127 memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info);
1128 return(memory_info);
1132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136 % R e s e t M a g i c k M e m o r y %
1140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1142 % ResetMagickMemory() fills the first size bytes of the memory area pointed to
1143 % by memory with the constant byte c.
1145 % The format of the ResetMagickMemory method is:
1147 % void *ResetMagickMemory(void *memory,int byte,const size_t size)
1149 % A description of each parameter follows:
1151 % o memory: a pointer to a memory allocation.
1153 % o byte: set the memory to this value.
1155 % o size: size of the memory to reset.
1158 MagickExport void *ResetMagickMemory(void *memory,int byte,const size_t size)
1160 assert(memory != (void *) NULL);
1161 return(memset(memory,byte,size));
1165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 % R e s i z e M a g i c k M e m o r y %
1173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1175 % ResizeMagickMemory() changes the size of the memory and returns a pointer to
1176 % the (possibly moved) block. The contents will be unchanged up to the
1177 % lesser of the new and old sizes.
1179 % The format of the ResizeMagickMemory method is:
1181 % void *ResizeMagickMemory(void *memory,const size_t size)
1183 % A description of each parameter follows:
1185 % o memory: A pointer to a memory allocation.
1187 % o size: the new size of the allocated memory.
1191 #if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1192 static inline void *ResizeBlock(void *block,size_t size)
1197 if (block == (void *) NULL)
1198 return(AcquireBlock(size));
1199 memory=AcquireBlock(size);
1200 if (memory == (void *) NULL)
1201 return((void *) NULL);
1202 if (size <= (SizeOfBlock(block)-sizeof(size_t)))
1203 (void) memcpy(memory,block,size);
1205 (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
1206 memory_pool.allocation+=size;
1211 MagickExport void *ResizeMagickMemory(void *memory,const size_t size)
1216 if (memory == (void *) NULL)
1217 return(AcquireMagickMemory(size));
1218 #if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1219 block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
1220 if (block == (void *) NULL)
1221 memory=RelinquishMagickMemory(memory);
1223 LockSemaphoreInfo(memory_semaphore);
1224 block=ResizeBlock(memory,size == 0 ? 1UL : size);
1225 if (block == (void *) NULL)
1227 if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
1229 UnlockSemaphoreInfo(memory_semaphore);
1230 memory=RelinquishMagickMemory(memory);
1231 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1233 block=ResizeBlock(memory,size == 0 ? 1UL : size);
1234 assert(block != (void *) NULL);
1236 UnlockSemaphoreInfo(memory_semaphore);
1237 memory=RelinquishMagickMemory(memory);
1243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247 % R e s i z e Q u a n t u m M e m o r y %
1251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253 % ResizeQuantumMemory() changes the size of the memory and returns a pointer
1254 % to the (possibly moved) block. The contents will be unchanged up to the
1255 % lesser of the new and old sizes.
1257 % The format of the ResizeQuantumMemory method is:
1259 % void *ResizeQuantumMemory(void *memory,const size_t count,
1260 % const size_t quantum)
1262 % A description of each parameter follows:
1264 % o memory: A pointer to a memory allocation.
1266 % o count: the number of quantum elements to allocate.
1268 % o quantum: the number of bytes in each quantum.
1271 MagickExport void *ResizeQuantumMemory(void *memory,const size_t count,
1272 const size_t quantum)
1277 if (HeapOverflowSanityCheck(count,quantum) != MagickFalse)
1279 memory=RelinquishMagickMemory(memory);
1280 return((void *) NULL);
1282 extent=count*quantum;
1283 return(ResizeMagickMemory(memory,extent));
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1291 % S e t M a g i c k M e m o r y M e t h o d s %
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 % SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy
1298 % memory. Your custom memory methods must be set prior to the
1299 % MagickCoreGenesis() method.
1301 % The format of the SetMagickMemoryMethods() method is:
1303 % SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler,
1304 % ResizeMemoryHandler resize_memory_handler,
1305 % DestroyMemoryHandler destroy_memory_handler)
1307 % A description of each parameter follows:
1309 % o acquire_memory_handler: method to acquire memory (e.g. malloc).
1311 % o resize_memory_handler: method to resize memory (e.g. realloc).
1313 % o destroy_memory_handler: method to destroy memory (e.g. free).
1316 MagickExport void SetMagickMemoryMethods(
1317 AcquireMemoryHandler acquire_memory_handler,
1318 ResizeMemoryHandler resize_memory_handler,
1319 DestroyMemoryHandler destroy_memory_handler)
1324 if (acquire_memory_handler != (AcquireMemoryHandler) NULL)
1325 memory_methods.acquire_memory_handler=acquire_memory_handler;
1326 if (resize_memory_handler != (ResizeMemoryHandler) NULL)
1327 memory_methods.resize_memory_handler=resize_memory_handler;
1328 if (destroy_memory_handler != (DestroyMemoryHandler) NULL)
1329 memory_methods.destroy_memory_handler=destroy_memory_handler;