1 /*
2 % Copyright (C) 2003-2020 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 % Copyright 1991-1999 E. I. du Pont de Nemours and Company
5 %
6 % This program is covered by multiple licenses, which are described in
7 % Copyright.txt. You should have received a copy of Copyright.txt with this
8 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9 %
10 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11 % %
12 % %
13 % %
14 % M M EEEEE M M OOO RRRR Y Y %
15 % MM MM E MM MM O O R R Y Y %
16 % M M M EEE M M M O O RRRR Y %
17 % M M E M M O O R R Y %
18 % M M EEEEE M M OOO R R Y %
19 % %
20 % %
21 % GraphicsMagick Memory Allocation Methods %
22 % %
23 % %
24 % Software Design %
25 % John Cristy %
26 % July 1998 %
27 % %
28 % %
29 % %
30 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31 %
32 %
33 %
34 */
35
36 /*
37 Include declarations.
38 */
39 #include "magick/studio.h"
40 #include "magick/resource.h"
41 #include "magick/utility.h"
42
43 #if defined(MAGICK_MEMORY_HARD_LIMIT)
44 #define MEMORY_LIMIT_CHECK(func,size) \
45 do \
46 { \
47 if (0) fprintf(stderr,"%s: %zu\n", func, size); \
48 if (size > (size_t)MAGICK_MEMORY_HARD_LIMIT) \
49 { \
50 fprintf(stderr,"%s: Excessive allocation request %zu\n", func, size); \
51 abort(); \
52 } \
53 } while(0)
54 #else
55 #define MEMORY_LIMIT_CHECK(func,size)
56 #endif /* MAGICK_MEMORY_HARD_LIMIT */
57
58 /*
59 Static variables.
60 */
61 static MagickFreeFunc FreeFunc = free;
62 static MagickMallocFunc MallocFunc = malloc;
63 static MagickReallocFunc ReallocFunc = realloc;
64
65 /*
66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67 % %
68 % %
69 % %
70 % M a g i c k A l l o c F u n c t i o n s %
71 % %
72 % %
73 % %
74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 %
76 % MagickAllocFunctions() provides a way for the user to supply a preferred
77 % free(), malloc(), and realloc() functions. Otherwise the default system
78 % versions are used. If an alternative allocator is to be used, this
79 % function should be invoked prior to invoking InitializeMagick().
80 %
81 % The format of the MagickAllocFunctions method is:
82 %
83 % void MagickAllocFunctions(MagickFreeFunc free_func,
84 % MagickMallocFunc malloc_func,
85 % MagickReallocFunc realloc_func)
86 %
87 % A description of each parameter follows:
88 %
89 % o free_func: Function to free memory.
90 %
91 % o malloc_func: Function to allocate memory.
92 %
93 % o realloc_func: Function to reallocate memory.
94 %
95 */
MagickAllocFunctions(MagickFreeFunc free_func,MagickMallocFunc malloc_func,MagickReallocFunc realloc_func)96 MagickExport void MagickAllocFunctions(MagickFreeFunc free_func,
97 MagickMallocFunc malloc_func,
98 MagickReallocFunc realloc_func)
99 {
100 FreeFunc = free_func;
101 MallocFunc = malloc_func;
102 ReallocFunc = realloc_func;
103 }
104
105 /*
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 % %
108 % %
109 % %
110 + M a g i c k A r r a y Si z e %
111 % %
112 % %
113 % %
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 %
116 % MagickArraySize() returnes the size of an array given two size_t arguments.
117 % Zero is returned if the computed result overflows the size_t type.
118 %
119 % The format of the MagickArraySize method is:
120 %
121 % size_t MagickArraySize(const size_t count, const size_t size);
122 %
123 % A description of each parameter follows:
124 %
125 % o count: The number of elements in the array.
126 %
127 % o size: The size of one array element.
128 %
129 */
MagickArraySize(const size_t count,const size_t size)130 MagickExport size_t MagickArraySize(const size_t count, const size_t size)
131 {
132 size_t
133 allocation_size;
134
135 allocation_size = size * count;
136 if ((count != 0) && (size != allocation_size/count))
137 allocation_size = 0;
138
139 return allocation_size;
140 }
141
142 /*
143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144 % %
145 % %
146 % %
147 % M a g i c k M a l l o c %
148 % %
149 % %
150 % %
151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152 %
153 % MagickMalloc() returns a pointer to a block of memory of at least size
154 % bytes suitably aligned for any use. NULL is returned if insufficient
155 % memory is available or the requested size is zero.
156 %
157 % The format of the MagickMalloc method is:
158 %
159 % void * MagickMalloc(const size_t size)
160 %
161 % A description of each parameter follows:
162 %
163 % o size: The size of the memory in bytes to allocate.
164 %
165 %
166 */
MagickMalloc(const size_t size)167 MagickExport void * MagickMalloc(const size_t size)
168 {
169 if (size == 0)
170 return ((void *) NULL);
171
172 /* fprintf(stderr,"%s %zu\n",__func__, size); */
173 MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
174
175 return (MallocFunc)(size);
176 }
177
178 /*
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 % %
181 % %
182 % %
183 % M a g i c k M a l l o c A l i g n e d %
184 % %
185 % %
186 % %
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 %
189 % MagickMallocAligned() allocates memory and returns a pointer to a
190 % block of memory capable of storing at least size bytes with the
191 % allocation's base address being an even multiple of alignment.
192 % The size of the buffer allocation is rounded up as required in
193 % order to consume a block of memory starting at least at the requested
194 % alignment and ending at at least the requested alignment.
195 %
196 % The requested alignment should be a power of 2 at least as large as
197 % sizeof a void pointer.
198 %
199 % NULL is returned if insufficient memory is available, the requested
200 % size is zero, or integer overflow was detected.
201 %
202 % This function is intended for allocating special-purpose buffers
203 % which benefit from specific alignment.
204 %
205 % The allocated memory should only be freed using MagickFreeAligned()
206 % and may not be reallocated.
207 %
208 % The format of the MagickMallocAligned method is:
209 %
210 % void * MagickMallocAligned(size_t alignment, const size_t size)
211 %
212 % A description of each parameter follows:
213 %
214 %
215 % o alignment: The alignment of the base and size of the allocated
216 % memory.
217 %
218 % o size: The size of the memory in bytes to allocate.
219 %
220 %
221 */
MagickMallocAligned(const size_t alignment,const size_t size)222 MagickExport void * MagickMallocAligned(const size_t alignment,const size_t size)
223 {
224 size_t
225 alligned_size;
226
227 void
228 *alligned_p = 0;
229
230 /* fprintf(stderr,"%s %zu\n",__func__, size); */
231 MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
232
233 alligned_size=RoundUpToAlignment(size,alignment);
234
235 if ((size == 0) || (alignment < sizeof(void *)) || (alligned_size < size))
236 return ((void *) NULL);
237
238 #if defined(HAVE_POSIX_MEMALIGN)
239 if (posix_memalign(&alligned_p, alignment, alligned_size) != 0)
240 alligned_p=0;
241 #elif defined(HAVE__ALIGNED_MALLOC)
242 alligned_p=_aligned_malloc(alligned_size,alignment);
243 #else
244 {
245 void
246 *alloc_p;
247
248 size_t
249 alloc_size;
250
251 alloc_size=(size+alignment-1)+sizeof(void *);
252 if (alloc_size > size)
253 {
254 if ((alloc_p = (MagickMalloc(alloc_size))) != NULL)
255 {
256 alligned_p=(void*) RoundUpToAlignment((magick_uintptr_t)alloc_p+
257 sizeof(void *),alignment);
258 *((void **)alligned_p-1)=alloc_p;
259 }
260 }
261 }
262 #endif
263
264 return alligned_p;
265 }
266
267 /*
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269 % %
270 % %
271 % %
272 + M a g i c k M a l l o c A l i g n e d A r r a y %
273 % %
274 % %
275 % %
276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 %
278 % MagickMallocAlignedArray() returns a pointer to a block of memory of
279 % sufficient size to support an array of elements of a specified size.
280 % The allocation's base address is an even multiple of the specified
281 % alignment. The size of the buffer allocation is rounded up as required
282 % in order to consume a block of memory starting at least at the requested
283 % alignment and ending at at least the requested alignment.
284 %
285 % NULL is returned if the required memory exceeds the range of size_t,
286 % the computed size is zero, or there is insufficient memory available.
287 %
288 % This function is intended for allocating special-purpose buffers
289 % which benefit from specific alignment.
290 %
291 % The allocated memory should only be freed using MagickFreeAligned()
292 % and may not be reallocated.
293 %
294 % The format of the MagickMallocArray method is:
295 %
296 % void *MagickMallocAlignedArray(const size_t alignment,
297 % const size_t count,
298 % const size_t size);
299 %
300 % A description of each parameter follows:
301 %
302 % o alignment: The alignment of the base and size of the allocated
303 % memory.
304 %
305 % o count: The number of elements in the array.
306 %
307 % o size: The size of one array element.
308 %
309 */
MagickMallocAlignedArray(const size_t alignment,const size_t count,const size_t size)310 MagickExport void *MagickMallocAlignedArray(const size_t alignment,
311 const size_t count,
312 const size_t size)
313 {
314 size_t
315 allocation_size;
316
317 void
318 *allocation;
319
320 allocation = (void *) NULL;
321 allocation_size=MagickArraySize(count,size);
322
323 if (allocation_size)
324 allocation = MagickMallocAligned(alignment,allocation_size);
325
326 return allocation;
327 }
328
329 /*
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331 % %
332 % %
333 % %
334 + M a g i c k M a l l o c A r r a y %
335 % %
336 % %
337 % %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 %
340 % MagickMallocArray() returns a pointer to a block of memory of
341 % sufficient size to support an array of elements of a specified size.
342 % The returned memory is suitably aligned for any use. NULL is returned
343 % if the required memory exceeds the range of size_t, the specified size
344 % is zero, or there is insufficient memory available.
345 %
346 % The format of the MagickMallocArray method is:
347 %
348 % void *MagickMallocArray(const size_t count, const size_t size);
349 %
350 % A description of each parameter follows:
351 %
352 % o count: The number of elements in the array.
353 %
354 % o size: The size of one array element.
355 %
356 */
MagickMallocArray(const size_t count,const size_t size)357 MagickExport void *MagickMallocArray(const size_t count,const size_t size)
358 {
359 size_t
360 allocation_size;
361
362 void
363 *allocation;
364
365 allocation = (void *) NULL;
366 allocation_size=MagickArraySize(count,size);
367
368 if (allocation_size)
369 allocation = MagickMalloc(allocation_size);
370 return allocation;
371 }
372
373 /*
374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375 % %
376 % %
377 % %
378 % M a g i c k M a l l o c C l e a r e d %
379 % %
380 % %
381 % %
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 %
384 % MagickMallocCleared() returns a pointer to a block of memory of at least
385 % size bytes suitably aligned for any use. NULL is returned if insufficient
386 % memory is available or the requested size is zero. This version differs
387 % from MagickMalloc in that the allocated bytes are cleared to zero.
388 %
389 % The format of the MagickMallocCleared method is:
390 %
391 % void * MagickMallocCleared(const size_t size)
392 %
393 % A description of each parameter follows:
394 %
395 % o size: The size of the memory in bytes to allocate.
396 %
397 %
398 */
MagickMallocCleared(const size_t size)399 MagickExport void * MagickMallocCleared(const size_t size)
400 {
401 void
402 *p = (void *) NULL;
403
404 if (size != 0)
405 {
406 p=MagickMalloc(size);
407
408 if (p != (void *) NULL)
409 (void) memset(p,0,size);
410 }
411
412 return p;
413 }
414
415 /*
416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 % %
418 % %
419 % %
420 % M a g i c k C l o n e M e m o r y %
421 % %
422 % %
423 % %
424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425 %
426 % MagickCloneMemory() copies size bytes from memory area source to the
427 % destination. Copying between objects that overlap will take place
428 % correctly. It returns destination.
429 %
430 % The format of the MagickCloneMemory method is:
431 %
432 % void *MagickCloneMemory(void *destination,const void *source,
433 % const size_t size)
434 %
435 % A description of each parameter follows:
436 %
437 % o size: The size of the memory in bytes to allocate.
438 %
439 %
440 */
MagickCloneMemory(void * destination,const void * source,const size_t size)441 MagickExport void *MagickCloneMemory(void *destination,const void *source,
442 const size_t size)
443 {
444 unsigned char
445 *d=(unsigned char*) destination;
446
447 const unsigned char
448 *s=(const unsigned char*) source;
449
450 assert(destination != (void *) NULL);
451 assert(source != (const void *) NULL);
452
453 if (((d+size) < s) || (d > (s+size)))
454 return(memcpy(destination,source,size));
455
456 return(memmove(destination,source,size));
457 }
458
459 /*
460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461 % %
462 % %
463 % %
464 % M a g i c k R e a l l o c %
465 % %
466 % %
467 % %
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469 %
470 % MagickRealloc() changes the size of the memory and returns a pointer to
471 % the (possibly moved) block. The contents will be unchanged up to the
472 % lesser of the new and old sizes. If size is zero, then the memory is
473 % freed and a NULL value is returned. If the memory allocation fails, then
474 % the existing memory is freed, and a NULL value is returned.
475 %
476 % Note that the behavior of this function is similar to BSD reallocf(3),
477 % see https://www.freebsd.org/cgi/man.cgi?query=reallocf
478 %
479 % The format of the MagickRealloc method is:
480 %
481 % void *MagickRealloc(void *memory,const size_t size)
482 %
483 % A description of each parameter follows:
484 %
485 % o memory: A pointer to a memory allocation.
486 %
487 % o size: The new size of the allocated memory.
488 %
489 */
MagickRealloc(void * memory,const size_t size)490 MagickExport void *MagickRealloc(void *memory,const size_t size)
491 {
492 void
493 *new_memory = (void *) NULL;
494
495 MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
496
497 if ((void *) NULL == memory)
498 new_memory = (MallocFunc)(size);
499 else
500 new_memory = (ReallocFunc)(memory,size);
501 if ((new_memory == 0) && (memory != 0) && (size != 0))
502 MagickFree(memory);
503
504 return new_memory;
505 }
506
507 /*
508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
509 % %
510 % %
511 % %
512 % M a g i c k F r e e %
513 % %
514 % %
515 % %
516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
517 %
518 % MagickFree() frees memory that has already been allocated by
519 % MagickMalloc() or other other other allocators directly compatible
520 % with the currently defined memory allocator (which defaults to the
521 % system malloc()). For convenience, a NULL argument is ignored.
522 %
523 % The format of the MagickFree method is:
524 %
525 % void MagickFree(void *memory)
526 %
527 % A description of each parameter follows:
528 %
529 % o memory: A pointer to a block of memory to free for reuse.
530 %
531 %
532 */
MagickFree(void * memory)533 MagickExport void MagickFree(void *memory)
534 {
535 if (memory != (void *) NULL)
536 (FreeFunc)(memory);
537 }
538
539 /*
540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 % %
542 % %
543 % %
544 % M a g i c k F r e e A l i g n e d %
545 % %
546 % %
547 % %
548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549 %
550 % MagickFreeAligned() frees aligned memory that has previously been
551 % allocated via MagickMallocAligned(). For convenience, a NULL argument is
552 % ignored.
553 %
554 % This function exists in case the pointer allocated by
555 % MagickMallocAligned() can not be used directly with MagickFree().
556 %
557 % The format of the MagickFreeAligned method is:
558 %
559 % void MagickFreeAligned(void *memory)
560 %
561 % A description of each parameter follows:
562 %
563 % o memory: A pointer to a block of memory to free for reuse.
564 %
565 %
566 */
MagickFreeAligned(void * memory)567 MagickExport void MagickFreeAligned(void *memory)
568 {
569 if (memory != (void *) NULL)
570 {
571 #if defined (HAVE_POSIX_MEMALIGN)
572 MagickFree(memory);
573 #elif defined(HAVE__ALIGNED_MALLOC)
574 /* Windows Studio .NET 2003 or later */
575 _aligned_free(memory);
576 #else
577 MagickFree(*((void **)memory-1));
578 #endif
579 }
580 }
581
582 /*
583 Structure for tracking resource-limited memory allocation.
584 */
585 typedef struct _MagickMemoryResource_T
586 {
587 void *memory; /* Pointer to memory allocation */
588 size_t alloc_size; /* Requested allocation size */
589 size_t alloc_size_real; /* Real/underlying allocation size */
590 size_t signature; /* Initialized to MagickSignature */
591
592 } MagickMemoryResource_T;
593
594 #if !defined(MAGICK_DEBUG_RL_MEMORY)
595 #define MAGICK_DEBUG_RL_MEMORY 0
596 #endif /* if !defined(MAGICK_DEBUG_RL_MEMORY) */
597
598 /* Return MemoryResource_T pointer given user-land pointer */
599 #define MagickAccessMemoryResource_T_From_Pub(p) \
600 ((MagickMemoryResource_T *) ((char *) p-sizeof(MagickMemoryResource_T)))
601 /* Return user-land pointer given private base allocation pointer */
602 #define UserLandPointerGivenBaseAlloc(p) \
603 ((char *)p+sizeof(MagickMemoryResource_T))
604 /* Trace MemoryResource_T content given a pointer to it */
605 #if defined(MAGICK_DEBUG_RL_MEMORY) && MAGICK_DEBUG_RL_MEMORY
606 #define TraceMagickAccessMemoryResource_T(operation,memory_resource) \
607 fprintf(stderr,__FILE__ ":%d - %s memory_resource: memory=%p (user %p)," \
608 " alloc_size=%zu," \
609 " alloc_size_real=%zu\n", \
610 __LINE__, \
611 operation, \
612 (memory_resource)->memory, \
613 (memory_resource)->memory ? UserLandPointerGivenBaseAlloc((memory_resource)->memory) : 0, \
614 (memory_resource)->alloc_size, \
615 (memory_resource)->alloc_size_real);
616 #else
617 #define TraceMagickAccessMemoryResource_T(operation,memory_resource) ;
618 #endif
619
620 /*
621 Clean up a MagickMemoryResource_T, releasing referenced memory and
622 resource allocation. Not safe if embedded in the memory buffer
623 being released!
624 */
_MagickFreeResourceLimitedMemory_T(MagickMemoryResource_T * memory_resource)625 static void _MagickFreeResourceLimitedMemory_T(MagickMemoryResource_T *memory_resource)
626 {
627 TraceMagickAccessMemoryResource_T("FREE",memory_resource);
628 if (memory_resource->memory != 0)
629 {
630 MagickFree(memory_resource->memory);
631 memory_resource->memory=0;
632 }
633 if (memory_resource->alloc_size != 0)
634 LiberateMagickResource(MemoryResource, memory_resource->alloc_size);
635 memory_resource->alloc_size_real=0;
636 memory_resource->alloc_size=0;
637 }
638
639
640 /*
641 Reallocate resource-limited array memory based on pointer to
642 existing allocation, object count, and object size. Freshly
643 allocated memory is cleared to zero if the clear flag is set.
644
645 This works like MagickRealloc() except for supporting count and size
646 arguments similar to calloc(). GNU libc has a reallocarray()
647 function using similar arguments.
648
649 Alignment concerns: 128-bit SSE registers have an alignment
650 requirement of 16 bytes, the 256-bit Intel AVX registers have an
651 alignment requirement of 32 bytes, and the 512-bit Intel AVX-512
652 registers have an alignment requirement of 64 bytes, that is.
653
654 Linux malloc produces allocations aligned to 16-bytes.
655 */
_MagickReallocateResourceLimitedMemory(void * p,const size_t count,const size_t size,const MagickBool clear)656 MagickExport void *_MagickReallocateResourceLimitedMemory(void *p,
657 const size_t count,
658 const size_t size,
659 const MagickBool clear)
660 {
661 MagickMemoryResource_T memory_resource;
662 size_t size_diff;
663 const size_t new_size = MagickArraySize(count,size);
664 void *res;
665 MagickPassFail
666 status = MagickPass;
667
668 #if defined(MAGICK_DEBUG_RL_MEMORY) && MAGICK_DEBUG_RL_MEMORY
669 fprintf(stderr,"%d: p = %p, count = %zu, size =%zu\n", __LINE__, p, count, size);
670 #endif
671
672 if (p != 0)
673 {
674 assert(((ptrdiff_t) p - sizeof(MagickMemoryResource_T)) > 0);
675 (void) memcpy(&memory_resource,
676 (void *) MagickAccessMemoryResource_T_From_Pub(p),
677 sizeof(MagickMemoryResource_T));
678 assert(memory_resource.signature == MagickSignature);
679 }
680 else
681 {
682 memory_resource.memory = 0;
683 memory_resource.alloc_size = 0;
684 memory_resource.alloc_size_real = 0;
685 memory_resource.signature = MagickSignature;
686 }
687 TraceMagickAccessMemoryResource_T("BEFORE", &memory_resource);
688
689 do
690 {
691 if (((new_size == 0) && (count != 0) && (size != 0)) ||
692 (new_size > SIZE_MAX/2) || (SIZE_MAX-new_size <= sizeof(MagickMemoryResource_T)))
693 {
694 /* Memory allocation FAILED */
695 #if defined(ENOMEM)
696 errno = ENOMEM;
697 #endif /* if defined(ENOMEM) */
698 status = MagickFail;
699 break;
700 }
701 else if (new_size == 0)
702 {
703 /* Deallocate all allocated memory (if any) */
704 _MagickFreeResourceLimitedMemory_T(&memory_resource);
705 break;
706 }
707 else if (new_size > memory_resource.alloc_size)
708 {
709 /* Allocate or enlarge memory */
710 size_diff = new_size - memory_resource.alloc_size;
711 if (AcquireMagickResource(MemoryResource,size_diff) == MagickPass)
712 {
713 if (new_size > memory_resource.alloc_size_real)
714 {
715 void *realloc_memory;
716 /* FIXME: Maybe over-allocate here if re-alloc? */
717 realloc_memory = (ReallocFunc)(memory_resource.memory,
718 new_size+sizeof(MagickMemoryResource_T));
719 if (realloc_memory != 0)
720 {
721 if (clear)
722 (void) memset(UserLandPointerGivenBaseAlloc(realloc_memory)+
723 memory_resource.alloc_size,0,size_diff);
724
725 memory_resource.memory = realloc_memory;
726 memory_resource.alloc_size = new_size;
727 memory_resource.alloc_size_real = new_size;
728 }
729 else
730 {
731 /* Memory re-allocation FAILED */
732 #if defined(ENOMEM)
733 errno = ENOMEM;
734 #endif /* if defined(ENOMEM) */
735 status = MagickFail;
736 }
737 }
738 else
739 {
740 if (clear)
741 (void) memset(UserLandPointerGivenBaseAlloc(memory_resource.memory)+
742 memory_resource.alloc_size,0,size_diff);
743
744 /* Re-allocation is not required */
745 memory_resource.alloc_size = new_size;
746 }
747 }
748 else
749 {
750 /* Acquire memory resource FAILED */
751 #if defined(ENOMEM)
752 errno = ENOMEM;
753 #endif /* if defined(ENOMEM) */
754 status = MagickFail;
755 }
756 break;
757 }
758 else if (new_size < memory_resource.alloc_size)
759 {
760 /* Reduce memory */
761 size_diff = memory_resource.alloc_size - new_size;
762 LiberateMagickResource(MemoryResource,size_diff);
763 memory_resource.alloc_size = new_size;
764 /* FIXME: Maybe actually realloc to smaller size here? */
765 break;
766 }
767 } while (0);
768
769 if (memory_resource.memory != 0)
770 {
771 (void) memcpy((void *) memory_resource.memory,&memory_resource,
772 sizeof(MagickMemoryResource_T));
773 }
774 TraceMagickAccessMemoryResource_T("AFTER", &memory_resource);
775
776 res = ((status == MagickPass) && memory_resource.memory) ?
777 UserLandPointerGivenBaseAlloc(memory_resource.memory) : 0;
778
779 return res;
780 }
781
782 /*
783 Allocate resource-limited memory. Similar to MagickMalloc().
784
785 Memory must be released using MagickFreeMemoryResource().
786 */
_MagickAllocateResourceLimitedMemory(const size_t size)787 MagickExport void *_MagickAllocateResourceLimitedMemory(const size_t size)
788 {
789 return _MagickReallocateResourceLimitedMemory(0,1,size,MagickFalse);
790 }
791
792 /*
793 Free resource-limited memory which was allocated by
794 MagickReallocMemoryResource() or MagickMallocMemoryResource().
795
796 Similar to MagickFree().
797 */
_MagickFreeResourceLimitedMemory(void * p)798 MagickExport void _MagickFreeResourceLimitedMemory(void *p)
799 {
800 _MagickReallocateResourceLimitedMemory(p,0,0,MagickFalse);
801 }
802