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