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