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