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