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