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