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