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