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