MagickCore 6.9.13-46
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 {
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#if !defined(STDERR_FILENO)
630#define STDERR_FILENO 2
631#endif
632
633 static const char fatal_message[] =
634 "ImageMagick: fatal error: unable to acquire critical memory\n";
635
636 void
637 *memory;
638
639 /*
640 Fail if memory request cannot be fulfilled.
641 */
642 memory=AcquireMagickMemory(size);
643 if (memory != (void *) NULL)
644 return(memory);
645 (void) write(STDERR_FILENO,fatal_message,sizeof(fatal_message)-1);
646 MagickCoreTerminus();
647 _exit(EXIT_FAILURE);
648}
649
650/*
651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
652% %
653% %
654% %
655% A c q u i r e Q u a n t u m M e m o r y %
656% %
657% %
658% %
659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
660%
661% AcquireQuantumMemory() returns a pointer to a block of memory at least
662% count * quantum bytes suitably aligned for any use.
663%
664% The format of the AcquireQuantumMemory method is:
665%
666% void *AcquireQuantumMemory(const size_t count,const size_t quantum)
667%
668% A description of each parameter follows:
669%
670% o count: the number of objects to allocate contiguously.
671%
672% o quantum: the size (in bytes) of each object.
673%
674*/
675MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
676{
677 size_t
678 size;
679
680 if ((HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse) ||
681 (size > GetMaxMemoryRequest()))
682 {
683 errno=ENOMEM;
684 return(NULL);
685 }
686 return(AcquireMagickMemory(size));
687}
688
689/*
690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691% %
692% %
693% %
694% A c q u i r e V i r t u a l M e m o r y %
695% %
696% %
697% %
698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699%
700% AcquireVirtualMemory() allocates a pointer to a block of memory at least
701% size bytes suitably aligned for any use. In addition to heap, it also
702% supports memory-mapped and file-based memory-mapped memory requests.
703%
704% The format of the AcquireVirtualMemory method is:
705%
706% MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum)
707%
708% A description of each parameter follows:
709%
710% o count: the number of objects to allocate contiguously.
711%
712% o quantum: the size (in bytes) of each object.
713%
714*/
715MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
716 const size_t quantum)
717{
718 char
719 *value;
720
721 MemoryInfo
722 *memory_info;
723
724 size_t
725 size;
726
727 if (HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse)
728 {
729 errno=ENOMEM;
730 return((MemoryInfo *) NULL);
731 }
732 if (virtual_anonymous_memory == 0)
733 {
734 virtual_anonymous_memory=1;
735 value=GetPolicyValue("system:memory-map");
736 if (LocaleCompare(value,"anonymous") == 0)
737 {
738 /*
739 The security policy sets anonymous mapping for the memory request.
740 */
741#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
742 virtual_anonymous_memory=2;
743#endif
744 }
745 value=DestroyString(value);
746 }
747 memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
748 sizeof(*memory_info)));
749 if (memory_info == (MemoryInfo *) NULL)
750 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
751 (void) memset(memory_info,0,sizeof(*memory_info));
752 memory_info->length=size;
753 memory_info->signature=MagickCoreSignature;
754 if ((virtual_anonymous_memory == 1) && (size <= GetMaxMemoryRequest()))
755 {
756 memory_info->blob=AcquireAlignedMemory(1,size);
757 if (memory_info->blob != NULL)
758 memory_info->type=AlignedVirtualMemory;
759 }
760 if (memory_info->blob == NULL)
761 {
762 /*
763 Acquire anonymous memory map.
764 */
765 memory_info->blob=NULL;
766 if (size <= GetMaxMemoryRequest())
767 memory_info->blob=MapBlob(-1,IOMode,0,size);
768 if (memory_info->blob != NULL)
769 memory_info->type=MapVirtualMemory;
770 else
771 {
772 int
773 file;
774
775 /*
776 Anonymous memory mapping failed, try file-backed memory mapping.
777 */
778 file=AcquireUniqueFileResource(memory_info->filename);
779 if (file != -1)
780 {
781 MagickOffsetType
782 offset;
783
784 offset=(MagickOffsetType) lseek(file,size-1,SEEK_SET);
785 if ((offset == (MagickOffsetType) (size-1)) &&
786 (write(file,"",1) == 1))
787 {
788#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
789 memory_info->blob=MapBlob(file,IOMode,0,size);
790#else
791 if (posix_fallocate(file,0,(MagickOffsetType) size) == 0)
792 memory_info->blob=MapBlob(file,IOMode,0,size);
793#endif
794 if (memory_info->blob != NULL)
795 memory_info->type=MapVirtualMemory;
796 else
797 {
798 (void) RelinquishUniqueFileResource(
799 memory_info->filename);
800 *memory_info->filename='\0';
801 }
802 }
803 (void) close(file);
804 }
805 }
806 }
807 if (memory_info->blob == NULL)
808 {
809 memory_info->blob=AcquireQuantumMemory(1,size);
810 if (memory_info->blob != NULL)
811 memory_info->type=UnalignedVirtualMemory;
812 }
813 if (memory_info->blob == NULL)
814 memory_info=RelinquishVirtualMemory(memory_info);
815 return(memory_info);
816}
817
818/*
819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
820% %
821% %
822% %
823% C o p y M a g i c k M e m o r y %
824% %
825% %
826% %
827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
828%
829% CopyMagickMemory() copies size bytes from memory area source to the
830% destination. Copying between objects that overlap will take place
831% correctly. It returns destination.
832%
833% The format of the CopyMagickMemory method is:
834%
835% void *CopyMagickMemory(void *magick_restrict destination,
836% const void *magick_restrict source,const size_t size)
837%
838% A description of each parameter follows:
839%
840% o destination: the destination.
841%
842% o source: the source.
843%
844% o size: the size of the memory in bytes to allocate.
845%
846*/
847MagickExport void *CopyMagickMemory(void *magick_restrict destination,
848 const void *magick_restrict source,const size_t size)
849{
850 const unsigned char
851 *p;
852
853 unsigned char
854 *q;
855
856 assert(destination != (void *) NULL);
857 assert(source != (const void *) NULL);
858 p=(const unsigned char *) source;
859 q=(unsigned char *) destination;
860 if (((q+size) < p) || (q > (p+size)))
861 switch (size)
862 {
863 default: return(memcpy(destination,source,size));
864 case 8: *q++=(*p++); magick_fallthrough;
865 case 7: *q++=(*p++); magick_fallthrough;
866 case 6: *q++=(*p++); magick_fallthrough;
867 case 5: *q++=(*p++); magick_fallthrough;
868 case 4: *q++=(*p++); magick_fallthrough;
869 case 3: *q++=(*p++); magick_fallthrough;
870 case 2: *q++=(*p++); magick_fallthrough;
871 case 1: *q++=(*p++); magick_fallthrough;
872 case 0: return(destination);
873 }
874 return(memmove(destination,source,size));
875}
876
877/*
878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879% %
880% %
881% %
882+ D e s t r o y M a g i c k M e m o r y %
883% %
884% %
885% %
886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
887%
888% DestroyMagickMemory() deallocates memory associated with the memory manager.
889%
890% The format of the DestroyMagickMemory method is:
891%
892% DestroyMagickMemory(void)
893%
894*/
895MagickExport void DestroyMagickMemory(void)
896{
897#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
898 ssize_t
899 i;
900
901 if (memory_semaphore == (SemaphoreInfo *) NULL)
902 ActivateSemaphoreInfo(&memory_semaphore);
903 LockSemaphoreInfo(memory_semaphore);
904 for (i=0; i < (ssize_t) memory_pool.number_segments; i++)
905 if (memory_pool.segments[i]->mapped == MagickFalse)
906 memory_methods.destroy_memory_handler(
907 memory_pool.segments[i]->allocation);
908 else
909 (void) UnmapBlob(memory_pool.segments[i]->allocation,
910 memory_pool.segments[i]->length);
911 free_segments=(DataSegmentInfo *) NULL;
912 (void) memset(&memory_pool,0,sizeof(memory_pool));
913 UnlockSemaphoreInfo(memory_semaphore);
914 DestroySemaphoreInfo(&memory_semaphore);
915#endif
916}
917
918#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
919/*
920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921% %
922% %
923% %
924+ E x p a n d H e a p %
925% %
926% %
927% %
928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929%
930% ExpandHeap() get more memory from the system. It returns MagickTrue on
931% success otherwise MagickFalse.
932%
933% The format of the ExpandHeap method is:
934%
935% MagickBooleanType ExpandHeap(size_t size)
936%
937% A description of each parameter follows:
938%
939% o size: the size of the memory in bytes we require.
940%
941*/
942static MagickBooleanType ExpandHeap(size_t size)
943{
944 DataSegmentInfo
945 *segment_info;
946
947 MagickBooleanType
948 mapped;
949
950 ssize_t
951 i;
952
953 void
954 *block;
955
956 size_t
957 blocksize;
958
959 void
960 *segment;
961
962 blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
963 assert(memory_pool.number_segments < MaxSegments);
964 segment=MapBlob(-1,IOMode,0,blocksize);
965 mapped=segment != (void *) NULL ? MagickTrue : MagickFalse;
966 if (segment == (void *) NULL)
967 segment=(void *) memory_methods.acquire_memory_handler(blocksize);
968 if (segment == (void *) NULL)
969 return(MagickFalse);
970 segment_info=(DataSegmentInfo *) free_segments;
971 free_segments=segment_info->next;
972 segment_info->mapped=mapped;
973 segment_info->length=blocksize;
974 segment_info->allocation=segment;
975 segment_info->bound=(char *) segment+blocksize;
976 i=(ssize_t) memory_pool.number_segments-1;
977 for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--)
978 memory_pool.segments[i+1]=memory_pool.segments[i];
979 memory_pool.segments[i+1]=segment_info;
980 memory_pool.number_segments++;
981 size=blocksize-12*sizeof(size_t);
982 block=(char *) segment_info->allocation+4*sizeof(size_t);
983 *BlockHeader(block)=size | PreviousBlockBit;
984 *BlockFooter(block,size)=size;
985 InsertFreeBlock(block,AllocationPolicy(size));
986 block=NextBlock(block);
987 assert(block < segment_info->bound);
988 *BlockHeader(block)=2*sizeof(size_t);
989 *BlockHeader(NextBlock(block))=PreviousBlockBit;
990 return(MagickTrue);
991}
992#endif
993
994/*
995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
996% %
997% %
998% %
999% G e t M a g i c k M e m o r y M e t h o d s %
1000% %
1001% %
1002% %
1003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1004%
1005% GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy
1006% memory.
1007%
1008% The format of the GetMagickMemoryMethods() method is:
1009%
1010% void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler,
1011% ResizeMemoryHandler *resize_memory_handler,
1012% DestroyMemoryHandler *destroy_memory_handler)
1013%
1014% A description of each parameter follows:
1015%
1016% o acquire_memory_handler: method to acquire memory (e.g. malloc).
1017%
1018% o resize_memory_handler: method to resize memory (e.g. realloc).
1019%
1020% o destroy_memory_handler: method to destroy memory (e.g. free).
1021%
1022*/
1023MagickExport void GetMagickMemoryMethods(
1024 AcquireMemoryHandler *acquire_memory_handler,
1025 ResizeMemoryHandler *resize_memory_handler,
1026 DestroyMemoryHandler *destroy_memory_handler)
1027{
1028 assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL);
1029 assert(resize_memory_handler != (ResizeMemoryHandler *) NULL);
1030 assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL);
1031 *acquire_memory_handler=memory_methods.acquire_memory_handler;
1032 *resize_memory_handler=memory_methods.resize_memory_handler;
1033 *destroy_memory_handler=memory_methods.destroy_memory_handler;
1034}
1035
1036/*
1037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038% %
1039% %
1040% %
1041+ G e t M a x M e m o r y R e q u e s t %
1042% %
1043% %
1044% %
1045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1046%
1047% GetMaxMemoryRequest() returns the max memory request value.
1048%
1049% The format of the GetMaxMemoryRequest method is:
1050%
1051% size_t GetMaxMemoryRequest(void)
1052%
1053*/
1054MagickExport size_t GetMaxMemoryRequest(void)
1055{
1056#define MinMemoryRequest "16MiB"
1057
1058 if (max_memory_request == 0)
1059 {
1060 char
1061 *value;
1062
1063 max_memory_request=(size_t) MAGICK_SSIZE_MAX;
1064 value=GetPolicyValue("system:max-memory-request");
1065 if (value != (char *) NULL)
1066 {
1067 /*
1068 The security policy sets a max memory request limit.
1069 */
1070 max_memory_request=MagickMax(StringToSizeType(value,100.0),
1071 StringToSizeType(MinMemoryRequest,100.0));
1072 value=DestroyString(value);
1073 }
1074 }
1075 return(MagickMin(max_memory_request,(size_t) MAGICK_SSIZE_MAX));
1076}
1077
1078/*
1079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080% %
1081% %
1082% %
1083% G e t V i r t u a l M e m o r y B l o b %
1084% %
1085% %
1086% %
1087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088%
1089% GetVirtualMemoryBlob() returns the virtual memory blob associated with the
1090% specified MemoryInfo structure.
1091%
1092% The format of the GetVirtualMemoryBlob method is:
1093%
1094% void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
1095%
1096% A description of each parameter follows:
1097%
1098% o memory_info: The MemoryInfo structure.
1099*/
1100MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
1101{
1102 assert(memory_info != (const MemoryInfo *) NULL);
1103 assert(memory_info->signature == MagickCoreSignature);
1104 return(memory_info->blob);
1105}
1106
1107/*
1108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109% %
1110% %
1111% %
1112% R e l i n q u i s h A l i g n e d M e m o r y %
1113% %
1114% %
1115% %
1116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117%
1118% RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory()
1119% or reuse.
1120%
1121% The format of the RelinquishAlignedMemory method is:
1122%
1123% void *RelinquishAlignedMemory(void *memory)
1124%
1125% A description of each parameter follows:
1126%
1127% o memory: A pointer to a block of memory to free for reuse.
1128%
1129*/
1130MagickExport void *RelinquishAlignedMemory(void *memory)
1131{
1132 if (memory == (void *) NULL)
1133 return((void *) NULL);
1134 if (memory_methods.relinquish_aligned_memory_handler != (RelinquishAlignedMemoryHandler) NULL)
1135 {
1136 memory_methods.relinquish_aligned_memory_handler(memory);
1137 return(NULL);
1138 }
1139#if defined(MAGICKCORE_HAVE_ALIGNED_MALLOC) || defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
1140 free(memory);
1141#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
1142 _aligned_free(memory);
1143#else
1144 RelinquishMagickMemory(actual_base_address(memory));
1145#endif
1146 return(NULL);
1147}
1148
1149/*
1150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1151% %
1152% %
1153% %
1154% R e l i n q u i s h M a g i c k M e m o r y %
1155% %
1156% %
1157% %
1158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1159%
1160% RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory()
1161% or AcquireQuantumMemory() for reuse.
1162%
1163% The format of the RelinquishMagickMemory method is:
1164%
1165% void *RelinquishMagickMemory(void *memory)
1166%
1167% A description of each parameter follows:
1168%
1169% o memory: A pointer to a block of memory to free for reuse.
1170%
1171*/
1172MagickExport void *RelinquishMagickMemory(void *memory)
1173{
1174 if (memory == (void *) NULL)
1175 return((void *) NULL);
1176#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1177 memory_methods.destroy_memory_handler(memory);
1178#else
1179 LockSemaphoreInfo(memory_semaphore);
1180 assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0);
1181 assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0);
1182 if ((*BlockHeader(memory) & PreviousBlockBit) == 0)
1183 {
1184 void
1185 *previous;
1186
1187 /*
1188 Coalesce with previous adjacent block.
1189 */
1190 previous=PreviousBlock(memory);
1191 RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous)));
1192 *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) |
1193 (*BlockHeader(previous) & ~SizeMask);
1194 memory=previous;
1195 }
1196 if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0)
1197 {
1198 void
1199 *next;
1200
1201 /*
1202 Coalesce with next adjacent block.
1203 */
1204 next=NextBlock(memory);
1205 RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next)));
1206 *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) |
1207 (*BlockHeader(memory) & ~SizeMask);
1208 }
1209 *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory);
1210 *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit);
1211 InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory)));
1212 UnlockSemaphoreInfo(memory_semaphore);
1213#endif
1214 return((void *) NULL);
1215}
1216
1217/*
1218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1219% %
1220% %
1221% %
1222% R e l i n q u i s h V i r t u a l M e m o r y %
1223% %
1224% %
1225% %
1226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1227%
1228% RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory().
1229%
1230% The format of the RelinquishVirtualMemory method is:
1231%
1232% MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1233%
1234% A description of each parameter follows:
1235%
1236% o memory_info: A pointer to a block of memory to free for reuse.
1237%
1238*/
1239MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1240{
1241 assert(memory_info != (MemoryInfo *) NULL);
1242 assert(memory_info->signature == MagickCoreSignature);
1243 if (memory_info->blob != (void *) NULL)
1244 switch (memory_info->type)
1245 {
1246 case AlignedVirtualMemory:
1247 {
1248 (void) ShredMagickMemory(memory_info->blob,memory_info->length);
1249 memory_info->blob=RelinquishAlignedMemory(memory_info->blob);
1250 break;
1251 }
1252 case MapVirtualMemory:
1253 {
1254 (void) UnmapBlob(memory_info->blob,memory_info->length);
1255 memory_info->blob=NULL;
1256 if (*memory_info->filename != '\0')
1257 (void) RelinquishUniqueFileResource(memory_info->filename);
1258 break;
1259 }
1260 case UnalignedVirtualMemory:
1261 default:
1262 {
1263 (void) ShredMagickMemory(memory_info->blob,memory_info->length);
1264 memory_info->blob=RelinquishMagickMemory(memory_info->blob);
1265 break;
1266 }
1267 }
1268 memory_info->signature=(~MagickCoreSignature);
1269 memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info);
1270 return(memory_info);
1271}
1272
1273/*
1274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1275% %
1276% %
1277% %
1278% R e s e t M a g i c k M e m o r y %
1279% %
1280% %
1281% %
1282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1283%
1284% ResetMagickMemory() fills the first size bytes of the memory area pointed to
1285% by memory with the constant byte c. We use a volatile pointer when
1286% updating the byte string. Most compilers will avoid optimizing away access
1287% to a volatile pointer, even if the pointer appears to be unused after the
1288% call.
1289%
1290% The format of the ResetMagickMemory method is:
1291%
1292% void *ResetMagickMemory(void *memory,int c,const size_t size)
1293%
1294% A description of each parameter follows:
1295%
1296% o memory: a pointer to a memory allocation.
1297%
1298% o c: set the memory to this value.
1299%
1300% o size: size of the memory to reset.
1301%
1302*/
1303MagickExport void *ResetMagickMemory(void *memory,int c,const size_t size)
1304{
1305 volatile unsigned char
1306 *p = (volatile unsigned char *) memory;
1307
1308 size_t
1309 n = size;
1310
1311 assert(memory != (void *) NULL);
1312 while (n-- != 0)
1313 *p++=(unsigned char) c;
1314 return(memory);
1315}
1316
1317/*
1318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1319% %
1320% %
1321% %
1322+ R e s e t M a x M e m o r y R e q u e s t %
1323% %
1324% %
1325% %
1326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327%
1328% ResetMaxMemoryRequest() resets the max_memory_request value.
1329%
1330% The format of the ResetMaxMemoryRequest method is:
1331%
1332% void ResetMaxMemoryRequest(void)
1333%
1334*/
1335MagickPrivate void ResetMaxMemoryRequest(void)
1336{
1337 max_memory_request=0;
1338}
1339
1340/*
1341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342% %
1343% %
1344% %
1345+ 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 %
1346% %
1347% %
1348% %
1349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1350%
1351% ResetVirtualAnonymousMemory() resets the virtual_anonymous_memory value.
1352%
1353% The format of the ResetVirtualAnonymousMemory method is:
1354%
1355% void ResetVirtualAnonymousMemory(void)
1356%
1357*/
1358MagickPrivate void ResetVirtualAnonymousMemory(void)
1359{
1360 virtual_anonymous_memory=0;
1361}
1362
1363/*
1364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365% %
1366% %
1367% %
1368% R e s i z e M a g i c k M e m o r y %
1369% %
1370% %
1371% %
1372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373%
1374% ResizeMagickMemory() changes the size of the memory and returns a pointer to
1375% the (possibly moved) block. The contents will be unchanged up to the
1376% lesser of the new and old sizes.
1377%
1378% The format of the ResizeMagickMemory method is:
1379%
1380% void *ResizeMagickMemory(void *memory,const size_t size)
1381%
1382% A description of each parameter follows:
1383%
1384% o memory: A pointer to a memory allocation.
1385%
1386% o size: the new size of the allocated memory.
1387%
1388*/
1389
1390#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1391static inline void *ResizeBlock(void *block,size_t size)
1392{
1393 void
1394 *memory;
1395
1396 if (block == (void *) NULL)
1397 return(AcquireBlock(size));
1398 memory=AcquireBlock(size);
1399 if (memory == (void *) NULL)
1400 return((void *) NULL);
1401 if (size <= (SizeOfBlock(block)-sizeof(size_t)))
1402 (void) memcpy(memory,block,size);
1403 else
1404 (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
1405 memory_pool.allocation+=size;
1406 return(memory);
1407}
1408#endif
1409
1410MagickExport void *ResizeMagickMemory(void *memory,const size_t size)
1411{
1412 void
1413 *block;
1414
1415 if (memory == (void *) NULL)
1416 return(AcquireMagickMemory(size));
1417#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1418 block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
1419 if (block == (void *) NULL)
1420 memory=RelinquishMagickMemory(memory);
1421#else
1422 LockSemaphoreInfo(memory_semaphore);
1423 block=ResizeBlock(memory,size == 0 ? 1UL : size);
1424 if (block == (void *) NULL)
1425 {
1426 if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
1427 {
1428 UnlockSemaphoreInfo(memory_semaphore);
1429 memory=RelinquishMagickMemory(memory);
1430 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1431 }
1432 block=ResizeBlock(memory,size == 0 ? 1UL : size);
1433 assert(block != (void *) NULL);
1434 }
1435 UnlockSemaphoreInfo(memory_semaphore);
1436 memory=RelinquishMagickMemory(memory);
1437#endif
1438 return(block);
1439}
1440
1441/*
1442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443% %
1444% %
1445% %
1446% R e s i z e Q u a n t u m M e m o r y %
1447% %
1448% %
1449% %
1450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451%
1452% ResizeQuantumMemory() changes the size of the memory and returns a pointer
1453% to the (possibly moved) block. The contents will be unchanged up to the
1454% lesser of the new and old sizes.
1455%
1456% The format of the ResizeQuantumMemory method is:
1457%
1458% void *ResizeQuantumMemory(void *memory,const size_t count,
1459% const size_t quantum)
1460%
1461% A description of each parameter follows:
1462%
1463% o memory: A pointer to a memory allocation.
1464%
1465% o count: the number of objects to allocate contiguously.
1466%
1467% o quantum: the size (in bytes) of each object.
1468%
1469*/
1470MagickExport void *ResizeQuantumMemory(void *memory,const size_t count,
1471 const size_t quantum)
1472{
1473 size_t
1474 size;
1475
1476 if ((HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse) ||
1477 (size > GetMaxMemoryRequest()))
1478 {
1479 errno=ENOMEM;
1480 memory=RelinquishMagickMemory(memory);
1481 return(NULL);
1482 }
1483 if (size > GetMaxMemoryRequest())
1484 return(NULL);
1485 return(ResizeMagickMemory(memory,size));
1486}
1487
1488/*
1489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1490% %
1491% %
1492% %
1493% 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 %
1494% %
1495% %
1496% %
1497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1498%
1499% SetMagickAlignedMemoryMethods() sets the methods to acquire and relinquish
1500% aligned memory.
1501%
1502% The format of the SetMagickAlignedMemoryMethods() method is:
1503%
1504% SetMagickAlignedMemoryMethods(
1505% AcquireAlignedMemoryHandler acquire_aligned_memory_handler,
1506% RelinquishAlignedMemoryHandler relinquish_aligned_memory_handler)
1507%
1508% A description of each parameter follows:
1509%
1510% o acquire_memory_handler: method to acquire aligned memory.
1511%
1512% o relinquish_aligned_memory_handler: method to relinquish aligned memory.
1513%
1514*/
1515MagickExport void SetMagickAlignedMemoryMethods(
1516 AcquireAlignedMemoryHandler acquire_aligned_memory_handler,
1517 RelinquishAlignedMemoryHandler relinquish_aligned_memory_handler)
1518{
1519 memory_methods.acquire_aligned_memory_handler=acquire_aligned_memory_handler;
1520 memory_methods.relinquish_aligned_memory_handler=
1521 relinquish_aligned_memory_handler;
1522}
1523
1524/*
1525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526% %
1527% %
1528% %
1529% S e t M a g i c k M e m o r y M e t h o d s %
1530% %
1531% %
1532% %
1533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534%
1535% SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy
1536% memory. Your custom memory methods must be set prior to the
1537% MagickCoreGenesis() method.
1538%
1539% The format of the SetMagickMemoryMethods() method is:
1540%
1541% SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler,
1542% ResizeMemoryHandler resize_memory_handler,
1543% DestroyMemoryHandler destroy_memory_handler)
1544%
1545% A description of each parameter follows:
1546%
1547% o acquire_memory_handler: method to acquire memory (e.g. malloc).
1548%
1549% o resize_memory_handler: method to resize memory (e.g. realloc).
1550%
1551% o destroy_memory_handler: method to destroy memory (e.g. free).
1552%
1553*/
1554MagickExport void SetMagickMemoryMethods(
1555 AcquireMemoryHandler acquire_memory_handler,
1556 ResizeMemoryHandler resize_memory_handler,
1557 DestroyMemoryHandler destroy_memory_handler)
1558{
1559 /*
1560 Set memory methods.
1561 */
1562 if (acquire_memory_handler != (AcquireMemoryHandler) NULL)
1563 memory_methods.acquire_memory_handler=acquire_memory_handler;
1564 if (resize_memory_handler != (ResizeMemoryHandler) NULL)
1565 memory_methods.resize_memory_handler=resize_memory_handler;
1566 if (destroy_memory_handler != (DestroyMemoryHandler) NULL)
1567 memory_methods.destroy_memory_handler=destroy_memory_handler;
1568}
1569
1570/*
1571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1572% %
1573% %
1574% %
1575+ S e t M a x M e m o r y R e q u e s t %
1576% %
1577% %
1578% %
1579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580%
1581% SetMaxMemoryRequest() sets the max_memory_request value.
1582%
1583% The format of the ResetMaxMemoryRequest method is:
1584%
1585% void SetMaxMemoryRequest(const MagickSizeType limit)
1586%
1587% A description of each parameter follows:
1588%
1589% o limit: the maximum memory request limit.
1590%
1591*/
1592MagickPrivate void SetMaxMemoryRequest(const MagickSizeType limit)
1593{
1594 max_memory_request=MagickMin(limit,GetMaxMemoryRequest());
1595}
1596
1597/*
1598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599% %
1600% %
1601% %
1602% S h r e d F i l e %
1603% %
1604% %
1605% %
1606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607%
1608% ShredMagickMemory() overwrites the specified memory buffer with random data.
1609% The overwrite is optional and is only required to help keep the contents of
1610% the memory buffer private.
1611%
1612% The format of the ShredMagickMemory method is:
1613%
1614% MagickBooleanType ShredMagickMemory(void *memory,const size_t length)
1615%
1616% A description of each parameter follows.
1617%
1618% o memory: Specifies the memory buffer.
1619%
1620% o length: Specifies the length of the memory buffer.
1621%
1622*/
1623MagickPrivate MagickBooleanType ShredMagickMemory(void *memory,
1624 const size_t length)
1625{
1626 RandomInfo
1627 *random_info;
1628
1629 size_t
1630 quantum;
1631
1632 ssize_t
1633 i;
1634
1635 StringInfo
1636 *key;
1637
1638 static ssize_t
1639 passes = -1;
1640
1641 if ((memory == NULL) || (length == 0))
1642 return(MagickFalse);
1643 if (passes == -1)
1644 {
1645 char
1646 *property;
1647
1648 passes=0;
1649 property=GetEnvironmentValue("MAGICK_SHRED_PASSES");
1650 if (property != (char *) NULL)
1651 {
1652 passes=(ssize_t) StringToInteger(property);
1653 property=DestroyString(property);
1654 }
1655 property=GetPolicyValue("system:shred");
1656 if (property != (char *) NULL)
1657 {
1658 passes=(ssize_t) StringToInteger(property);
1659 property=DestroyString(property);
1660 }
1661 }
1662 if (passes == 0)
1663 return(MagickTrue);
1664 /*
1665 Overwrite the memory buffer with random data.
1666 */
1667 quantum=(size_t) MagickMin(length,MagickMinBufferExtent);
1668 random_info=AcquireRandomInfo();
1669 key=GetRandomKey(random_info,quantum);
1670 for (i=0; i < passes; i++)
1671 {
1672 size_t
1673 j;
1674
1675 unsigned char
1676 *p = (unsigned char *) memory;
1677
1678 for (j=0; j < length; j+=quantum)
1679 {
1680 if (i != 0)
1681 SetRandomKey(random_info,quantum,GetStringInfoDatum(key));
1682 (void) memcpy(p,GetStringInfoDatum(key),(size_t)
1683 MagickMin(quantum,length-j));
1684 p+=(ptrdiff_t) quantum;
1685 }
1686 if (j < length)
1687 break;
1688 }
1689 key=DestroyStringInfo(key);
1690 random_info=DestroyRandomInfo(random_info);
1691 return(i < passes ? MagickFalse : MagickTrue);
1692}