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