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