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