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