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