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