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