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