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