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