Coverage Report

Created: 2025-12-03 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/magick/memory.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2025 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
*/
96
MagickExport void MagickAllocFunctions(MagickFreeFunc free_func,
97
                                       MagickMallocFunc malloc_func,
98
                                       MagickReallocFunc realloc_func)
99
0
{
100
0
  FreeFunc    = free_func;
101
0
  MallocFunc  = malloc_func;
102
0
  ReallocFunc = realloc_func;
103
0
}
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() returns 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
*/
130
MagickExport size_t MagickArraySize(const size_t count, const size_t size)
131
573M
{
132
573M
  size_t
133
573M
    allocation_size;
134
135
573M
  allocation_size = size * count;
136
573M
  if ((count != 0) && (size != allocation_size/count))
137
5
    allocation_size = 0;
138
139
573M
  return allocation_size;
140
573M
}
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
*/
167
MagickExport void * MagickMalloc(const size_t size)
168
203M
{
169
203M
  if (size == 0)
170
0
    return ((void *) NULL);
171
172
  /* fprintf(stderr,"%s %zu\n",__func__, size); */
173
203M
  MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
174
175
203M
  return (MallocFunc)(size);
176
203M
}
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
*/
222
MagickExport void * MagickMallocAligned(const size_t alignment,const size_t size)
223
110M
{
224
110M
  size_t
225
110M
    alligned_size;
226
227
110M
  void
228
110M
    *alligned_p = 0;
229
230
  /* fprintf(stderr,"%s %zu\n",__func__, size); */
231
110M
  MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
232
233
110M
  alligned_size=RoundUpToAlignment(size,alignment);
234
235
110M
  if ((size == 0) || (alignment < sizeof(void *)) || (alligned_size < size))
236
0
    return ((void *) NULL);
237
238
110M
#if defined(HAVE_POSIX_MEMALIGN)
239
110M
  if (posix_memalign(&alligned_p, alignment, alligned_size) != 0)
240
0
    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
110M
  return alligned_p;
265
110M
}
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
*/
310
MagickExport void *MagickMallocAlignedArray(const size_t alignment,
311
                                            const size_t count,
312
                                            const size_t size)
313
0
{
314
0
  size_t
315
0
    allocation_size;
316
317
0
  void
318
0
    *allocation;
319
320
0
  allocation = (void *) NULL;
321
0
  allocation_size=MagickArraySize(count,size);
322
323
0
  if (allocation_size)
324
0
    allocation = MagickMallocAligned(alignment,allocation_size);
325
326
0
  return allocation;
327
0
}
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
*/
357
MagickExport void *MagickMallocArray(const size_t count,const size_t size)
358
17.4M
{
359
17.4M
  size_t
360
17.4M
    allocation_size;
361
362
17.4M
  void
363
17.4M
    *allocation;
364
365
17.4M
  allocation = (void *) NULL;
366
17.4M
  allocation_size=MagickArraySize(count,size);
367
368
17.4M
  if (allocation_size)
369
17.4M
    allocation = MagickMalloc(allocation_size);
370
17.4M
  return allocation;
371
17.4M
}
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
*/
399
MagickExport void * MagickMallocCleared(const size_t size)
400
32.5M
{
401
32.5M
  void
402
32.5M
    *p = (void *) NULL;
403
404
32.5M
  if (size != 0)
405
32.5M
    {
406
32.5M
      p=MagickMalloc(size);
407
408
32.5M
      if (p != (void *) NULL)
409
32.5M
        (void) memset(p,0,size);
410
32.5M
    }
411
412
32.5M
  return p;
413
32.5M
}
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
*/
441
MagickExport void *MagickCloneMemory(void *destination,const void *source,
442
  const size_t size)
443
0
{
444
0
  unsigned char
445
0
    *d=(unsigned char*) destination;
446
447
0
  const unsigned char
448
0
    *s=(const unsigned char*) source;
449
450
0
  assert(destination != (void *) NULL);
451
0
  assert(source != (const void *) NULL);
452
453
0
  if (((d+size) < s) || (d > (s+size)))
454
0
    return(memcpy(destination,source,size));
455
456
0
  return(memmove(destination,source,size));
457
0
}
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
%  a NULL value is returned.
475
%
476
%  Note that the behavior of this function is similar to ANSI C realloc(3).
477
%  If NULL is returned, then the original memory pointer value is still
478
%  valid.
479
%
480
%  The behavor of this function has changed given that it used to free the
481
%  memory upon allocation failure.  This dubious responsibility has now been
482
%  delegated to the MagickReallocMemory() macro.
483
%
484
%  The format of the MagickRealloc method is:
485
%
486
%      void *MagickRealloc(void *memory,const size_t size)
487
%
488
%  A description of each parameter follows:
489
%
490
%    o memory: A pointer to a memory allocation.
491
%
492
%    o size: The new size of the allocated memory.
493
%
494
*/
495
MagickExport void *MagickRealloc(void *memory,const size_t size)
496
4.16M
{
497
4.16M
  void
498
4.16M
    *new_memory = (void *) NULL;
499
500
4.16M
  MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
501
502
4.16M
  if ((void *) NULL == memory)
503
608k
    new_memory = (MallocFunc)(size);
504
3.55M
  else
505
3.55M
    new_memory = (ReallocFunc)(memory,size);
506
4.16M
  if ((new_memory == 0) && (memory != 0) && (size != 0))
507
0
    MagickFree(memory);
508
509
4.16M
  return new_memory;
510
4.16M
}
511

512
/*
513
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514
%                                                                             %
515
%                                                                             %
516
%                                                                             %
517
%    M a g i c k F r e e                                                      %
518
%                                                                             %
519
%                                                                             %
520
%                                                                             %
521
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522
%
523
%  MagickFree() frees memory that has already been allocated by
524
%  MagickMalloc() or other other other allocators directly compatible
525
%  with the currently defined memory allocator (which defaults to the
526
%  system malloc()). For convenience, a NULL argument is ignored.
527
%
528
%  The format of the MagickFree method is:
529
%
530
%      void MagickFree(void *memory)
531
%
532
%  A description of each parameter follows:
533
%
534
%    o memory: A pointer to a block of memory to free for reuse.
535
%
536
%
537
*/
538
MagickExport void MagickFree(void *memory)
539
1.09G
{
540
1.09G
  if (memory != (void *) NULL)
541
568M
    (FreeFunc)(memory);
542
1.09G
}
543

544
/*
545
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546
%                                                                             %
547
%                                                                             %
548
%                                                                             %
549
%    M a g i c k F r e e A l i g n e d                                        %
550
%                                                                             %
551
%                                                                             %
552
%                                                                             %
553
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554
%
555
%  MagickFreeAligned() frees aligned memory that has previously been
556
%  allocated via MagickMallocAligned(). For convenience, a NULL argument is
557
%  ignored.
558
%
559
%  This function exists in case the pointer allocated by
560
%  MagickMallocAligned() can not be used directly with MagickFree().
561
%
562
%  The format of the MagickFreeAligned method is:
563
%
564
%      void MagickFreeAligned(void *memory)
565
%
566
%  A description of each parameter follows:
567
%
568
%    o memory: A pointer to a block of memory to free for reuse.
569
%
570
%
571
*/
572
MagickExport void MagickFreeAligned(void *memory)
573
131M
{
574
131M
  if (memory != (void *) NULL)
575
110M
    {
576
110M
#if defined (HAVE_POSIX_MEMALIGN)
577
110M
      MagickFree(memory);
578
#elif defined(HAVE__ALIGNED_MALLOC)
579
      /* Windows Studio .NET 2003 or later */
580
      _aligned_free(memory);
581
#else
582
      MagickFree(*((void **)memory-1));
583
#endif
584
110M
    }
585
131M
}
586
587
/*
588
  Structure for tracking resource-limited memory allocation.
589
 */
590
typedef struct _MagickMemoryResource_T
591
{
592
  void *memory;                     /* Pointer to memory allocation */
593
  size_t alloc_size_initial;        /* Initially requested allocation size */
594
  size_t alloc_size;                /* Requested allocation size */
595
  size_t alloc_size_limit;          /* Limit on maximum alloc_size */
596
  size_t alloc_size_real;           /* Real/underlying allocation size */
597
  const char *alloc_module;         /* Source file of first allocation */
598
  const char *alloc_function;       /* Name of function which made first allocation */
599
  unsigned int alloc_line;          /* Source file line of first allocation */
600
  size_t num_realloc;               /* Number of actual reallocations performed */
601
  size_t num_realloc_limit;         /* Limit on number of reallocations */
602
  size_t num_realloc_moves;         /* Number of reallocations which moved memory */
603
  size_t num_realloc_moves_limit;   /* Limit on number of reallocations which required move */
604
  size_t realloc_octets_moved;      /* Number of octets moved by reallocations */
605
  size_t signature;                 /* Initialized to MagickSignature */
606
607
} MagickMemoryResource_T;
608
609
#if !defined(MAGICK_DEBUG_RL_MEMORY)
610
#define MAGICK_DEBUG_RL_MEMORY 0
611
#endif /* if !defined(MAGICK_DEBUG_RL_MEMORY) */
612
613
/* Return MemoryResource_T pointer given user-land pointer */
614
#define MagickAccessMemoryResource_T_From_Pub(p) \
615
261M
  ((MagickMemoryResource_T *) ((char *) p-sizeof(MagickMemoryResource_T)))
616
617
/* Return user-land pointer given private base allocation pointer */
618
#define UserLandPointerGivenBaseAlloc(p) \
619
262M
  ((char *)p+sizeof(MagickMemoryResource_T))
620
621
/* Copy (or init) MagickMemoryResource_T based on provided user-land pointer */
622
#define MagickCopyMemoryResource_T_From_Pub(module,function,line,memory_resource, p)         \
623
550M
  do {                                                                  \
624
550M
    if (p != 0)                                                         \
625
550M
      {                                                                 \
626
261M
        assert(((ptrdiff_t) p - sizeof(MagickMemoryResource_T)) > 0);   \
627
261M
        (void) memcpy(memory_resource,                                  \
628
261M
                      (void *) MagickAccessMemoryResource_T_From_Pub(p), \
629
261M
                      sizeof(MagickMemoryResource_T));                  \
630
261M
        assert((memory_resource)->signature == MagickSignature);        \
631
261M
      }                                                                 \
632
550M
    else                                                                \
633
550M
      {                                                                 \
634
288M
        (memory_resource)->memory = 0;                                  \
635
288M
        (memory_resource)->alloc_size_initial = 0;                      \
636
288M
        (memory_resource)->alloc_size = 0;                              \
637
288M
        (memory_resource)->alloc_size_limit = SIZE_MAX;                 \
638
288M
        (memory_resource)->alloc_size_real = 0;                         \
639
288M
        (memory_resource)->alloc_module = module;                       \
640
288M
        (memory_resource)->alloc_function = function;                   \
641
288M
        (memory_resource)->alloc_line = line;                           \
642
288M
        (memory_resource)->num_realloc = 0;                             \
643
288M
        (memory_resource)->num_realloc_limit = SIZE_MAX;                \
644
288M
        (memory_resource)->num_realloc_moves = 0;                       \
645
288M
        (memory_resource)->num_realloc_moves_limit = SIZE_MAX;          \
646
288M
        (memory_resource)->realloc_octets_moved = 0;                    \
647
288M
        (memory_resource)->signature = MagickSignature;                 \
648
288M
      }                                                                 \
649
550M
  } while(0)
650
651
/* Trace MemoryResource_T content given a pointer to it */
652
#if defined(MAGICK_DEBUG_RL_MEMORY) && MAGICK_DEBUG_RL_MEMORY
653
#define TraceMagickAccessMemoryResource_T(module,function,line,operation,memory_resource) \
654
  fprintf(stderr,"%s/%s/%u: - %s memory_resource: memory=%p (user %p)," \
655
          " alloc_size_initial=%zu,"                                    \
656
          " alloc_size=%zu,"                                            \
657
          " alloc_size_real=%zu,"                                       \
658
          " alloc_module=%s,"                                           \
659
          " alloc_function=%s,"                                         \
660
          " alloc_line=%u,"                                             \
661
          " num_realloc=%zu,"                                           \
662
          " num_realloc_moves=%zu,"                                     \
663
          " realloc_octets_moved=%zu\n",                                \
664
          module,                                                       \
665
          function,                                                     \
666
          line,                                                         \
667
          operation,                                                    \
668
          (memory_resource)->memory,                                    \
669
          (memory_resource)->memory ? UserLandPointerGivenBaseAlloc((memory_resource)->memory) : 0, \
670
          (memory_resource)->alloc_size_initial,                        \
671
          (memory_resource)->alloc_size,                                \
672
          (memory_resource)->alloc_size_real,                           \
673
          (memory_resource)->alloc_module,                              \
674
          (memory_resource)->alloc_function,                            \
675
          (memory_resource)->alloc_line,                                \
676
          (memory_resource)->num_realloc,                               \
677
          (memory_resource)->num_realloc_moves,                         \
678
          (memory_resource)->realloc_octets_moved);
679
#else
680
1.38G
#define TraceMagickAccessMemoryResource_T(module,function,line,operation,memory_resource) ;
681
#endif
682
683
/*
684
  Clean up a MagickMemoryResource_T, releasing referenced memory and
685
  resource allocation.  Not safe if embedded in the memory buffer
686
  being released!
687
*/
688
static void _MagickFreeResourceLimitedMemory_T(const char *module,const char *function,const unsigned int line,
689
                                               MagickMemoryResource_T *memory_resource)
690
288M
{
691
288M
  TraceMagickAccessMemoryResource_T(module,function,line,"FREE",memory_resource);
692
288M
#if !(defined(MAGICK_DEBUG_RL_MEMORY) && MAGICK_DEBUG_RL_MEMORY)
693
288M
  (void) module;
694
288M
  (void) function;
695
288M
  (void) line;
696
288M
#endif
697
#if defined(MAGICK_MEMORY_LOG_REALLOC_STATS) && MAGICK_MEMORY_LOG_REALLOC_STATS
698
  if (memory_resource->num_realloc > 0)
699
    {
700
      const char
701
        *alloc_module,
702
        *modulebase;
703
704
      /* fixup module info to just include the filename - and not the
705
         whole path to the file. This makes the log huge for no good
706
         reason */
707
      alloc_module=(memory_resource)->alloc_module;
708
      for (modulebase=alloc_module+strlen(alloc_module)-1; modulebase > alloc_module; modulebase--)
709
        if (IsBasenameSeparator(*modulebase))
710
          {
711
            modulebase++;
712
            break;
713
          }
714
715
      fprintf(stderr,
716
              "%s/%s/%u FreeResourceLimitedMemory:"
717
              " alloc_initial=%zu,"
718
              " alloc_size=%zu,"
719
              " alloc_size_real=%zu,"
720
              " num_realloc=%zu,"
721
              " num_realloc_moves=%zu,"
722
              " realloc_octets_moved=%zu\n",
723
              modulebase,
724
              (memory_resource)->alloc_function,
725
              (memory_resource)->alloc_line,
726
              (memory_resource)->alloc_size_initial,
727
              (memory_resource)->alloc_size,
728
              (memory_resource)->alloc_size_real+sizeof(MagickMemoryResource_T),
729
              (memory_resource)->num_realloc,
730
              (memory_resource)->num_realloc_moves,
731
              (memory_resource)->realloc_octets_moved);
732
    }
733
#endif /* defined(MAGICK_MEMORY_LOG_REALLOC_STATS) && MAGICK_MEMORY_LOG_REALLOC_STATS */
734
288M
  if (memory_resource->memory != 0)
735
254M
    {
736
254M
      MagickFree(memory_resource->memory);
737
254M
      memory_resource->memory=0;
738
254M
    }
739
288M
  if (memory_resource->alloc_size != 0)
740
254M
    LiberateMagickResource(MemoryResource, memory_resource->alloc_size);
741
288M
  memory_resource->alloc_size_real = 0;
742
288M
  memory_resource->alloc_size_limit = SIZE_MAX;
743
288M
  memory_resource->alloc_size_initial = 0;
744
288M
  memory_resource->alloc_size = 0;
745
288M
  memory_resource->num_realloc = 0;
746
288M
  memory_resource->num_realloc_limit = SIZE_MAX;
747
288M
  memory_resource->num_realloc_moves = 0;
748
288M
  memory_resource->num_realloc_moves_limit = SIZE_MAX;
749
288M
  memory_resource->realloc_octets_moved = 0;
750
288M
}
751
752
753
/*
754
  Reallocate resource-limited array memory based on pointer to
755
  existing allocation, object count, and object size.  Freshly
756
  allocated memory is cleared to zero if the clear flag is set.
757
758
  This works like MagickRealloc() except for supporting count and size
759
  arguments similar to calloc().  GNU libc has a reallocarray()
760
  function using similar arguments. A pointer to the (possibly) new
761
  allocation is returned, so if NULL is returned, the previous pointer
762
  remains valid, similar to realloc().
763
764
  Alignment concerns: 128-bit SSE registers have an alignment
765
  requirement of 16 bytes, the 256-bit Intel AVX registers have an
766
  alignment requirement of 32 bytes, and the 512-bit Intel AVX-512
767
  registers have an alignment requirement of 64 bytes, that is.
768
769
  Linux malloc produces allocations aligned to 16-bytes.
770
 */
771
772
MagickExport void *_MagickReallocateResourceLimitedMemoryLoc(void *p,
773
                                                             const size_t count,
774
                                                             const size_t size,
775
                                                             const MagickBool clear,
776
                                                             const char *module,
777
                                                             const char *function,
778
                                                             const unsigned int line)
779
550M
{
780
550M
  MagickMemoryResource_T memory_resource;
781
550M
  size_t size_diff;
782
550M
  const size_t new_size =  MagickArraySize(count,size);
783
550M
  void *res;
784
550M
  MagickPassFail
785
550M
    status = MagickPass;
786
787
#if defined(MAGICK_DEBUG_RL_MEMORY) && MAGICK_DEBUG_RL_MEMORY
788
  fprintf(stderr,"%s/%s/%u: p = %p, count = %zu, size = %zu\n", module, function, line, p, count, size);
789
#endif
790
791
  /* Copy (or init) 'memory_resource' based on provided user-land pointer */
792
550M
  MagickCopyMemoryResource_T_From_Pub(module,function,line,&memory_resource, p);
793
550M
  TraceMagickAccessMemoryResource_T(module,function,line,"BEFORE",&memory_resource);
794
795
550M
  do
796
550M
    {
797
550M
      if (((new_size == 0) && (count != 0) && (size != 0)) ||
798
550M
          (new_size > SIZE_MAX/2) ||
799
550M
          (SIZE_MAX-new_size <= sizeof(MagickMemoryResource_T)) ||
800
550M
          (new_size > memory_resource.alloc_size_limit))
801
278
        {
802
          /* Memory allocation FAILED */
803
278
#if defined(ENOMEM)
804
278
          errno = ENOMEM;
805
278
#endif /* if defined(ENOMEM) */
806
278
          status = MagickFail;
807
278
          break;
808
278
        }
809
550M
      else if (new_size == 0)
810
288M
        {
811
          /* Deallocate all allocated memory (if any) */
812
288M
          _MagickFreeResourceLimitedMemory_T(module,function,line,&memory_resource);
813
288M
          break;
814
288M
        }
815
261M
      else if (new_size > memory_resource.alloc_size)
816
259M
        {
817
          /* Allocate or enlarge memory */
818
259M
          size_diff = new_size - memory_resource.alloc_size;
819
259M
          if (AcquireMagickResource(MemoryResource,size_diff) == MagickPass)
820
259M
            {
821
259M
              if (new_size > memory_resource.alloc_size_real)
822
255M
                {
823
255M
                  void *realloc_memory;
824
255M
                  size_t realloc_size = new_size+sizeof(MagickMemoryResource_T);
825
255M
                  if (memory_resource.alloc_size_real != 0)
826
1.45M
                    {
827
                      /* This is a realloc */
828
829
                      /* If number of allocations will exceed reallocation limit */
830
1.45M
                      if (memory_resource.num_realloc+1U > memory_resource.num_realloc_limit)
831
0
                        {
832
                          /* Force a de-alloc, resulting in "Memory re-allocation FAILED" */
833
0
                          realloc_size = 0;
834
0
                        }
835
1.45M
                      else
836
1.45M
                        {
837
                          /* Round up underlying allocation sizes in
838
                             order to lessen realloc calls and lessen
839
                             memory moves.
840
                          */
841
                          /* realloc_size <<= 1; */
842
1.45M
                          MagickRoundUpStringLength(realloc_size);
843
1.45M
                        }
844
1.45M
                    }
845
255M
                  realloc_memory = (ReallocFunc)(memory_resource.memory,
846
255M
                                                 realloc_size);
847
                  /* If number of realloc moves exceeds num_realloc_moves_limit */
848
255M
                  if ((realloc_memory != 0) && (memory_resource.alloc_size_real != 0) &&
849
1.45M
                      (realloc_memory != memory_resource.memory))
850
1.12M
                    {
851
1.12M
                      if (memory_resource.num_realloc_moves+1U > memory_resource.num_realloc_moves_limit)
852
0
                        {
853
                          /* Deallocate all allocated memory*/
854
0
                          realloc_memory = (ReallocFunc)(memory_resource.memory,0);
855
0
                        }
856
1.12M
                    }
857
255M
                  if ((realloc_memory != 0) && (realloc_size != 0))
858
255M
                    {
859
255M
                      if (clear)
860
499k
                        (void) memset(UserLandPointerGivenBaseAlloc(realloc_memory)+
861
499k
                                      memory_resource.alloc_size,0,size_diff);
862
863
                      /* A realloc has pre-existing memory */
864
255M
                      if (memory_resource.alloc_size_real != 0)
865
1.45M
                        {
866
                          /* Tally actual reallocations */
867
1.45M
                          memory_resource.num_realloc++;
868
                          /* Tally reallocations which resulted in a memory move */
869
1.45M
                          if (realloc_memory != memory_resource.memory)
870
1.12M
                            {
871
1.12M
                              memory_resource.num_realloc_moves++;
872
1.12M
                              memory_resource.realloc_octets_moved +=
873
1.12M
                                memory_resource.alloc_size_real+sizeof(MagickMemoryResource_T);
874
1.12M
                            }
875
1.45M
                        }
876
255M
                      memory_resource.memory = realloc_memory;
877
255M
                      if (memory_resource.alloc_size == 0)
878
254M
                        memory_resource.alloc_size_initial = new_size;
879
255M
                      memory_resource.alloc_size = new_size;
880
255M
                      memory_resource.alloc_size_real = realloc_size-sizeof(MagickMemoryResource_T);
881
255M
                    }
882
0
                  else
883
0
                    {
884
                      /* Memory re-allocation FAILED */
885
0
#if defined(ENOMEM)
886
0
                      errno = ENOMEM;
887
0
#endif /* if defined(ENOMEM) */
888
0
                      status = MagickFail;
889
0
                    }
890
255M
                }
891
4.17M
              else
892
4.17M
                {
893
4.17M
                   if (clear)
894
5.51k
                     (void) memset(UserLandPointerGivenBaseAlloc(memory_resource.memory)+
895
5.51k
                                   memory_resource.alloc_size,0,size_diff);
896
897
                  /* Re-allocation is not required */
898
4.17M
                  memory_resource.alloc_size = new_size;
899
4.17M
                }
900
259M
            }
901
630
          else
902
630
            {
903
              /*
904
                Acquire memory resource FAILED.  If this was a
905
                realloc, it is expected that the original pointer is
906
                valid and retained by the user, who will responsibly
907
                free it so its resource allocation will be released
908
                later.
909
              */
910
630
#if defined(ENOMEM)
911
630
              errno = ENOMEM;
912
630
#endif /* if defined(ENOMEM) */
913
630
              status = MagickFail;
914
630
            }
915
259M
          break;
916
259M
        }
917
1.92M
      else if (new_size < memory_resource.alloc_size)
918
408k
        {
919
          /* Reduce memory */
920
408k
          size_diff = memory_resource.alloc_size - new_size;
921
408k
          LiberateMagickResource(MemoryResource,size_diff);
922
408k
          memory_resource.alloc_size = new_size;
923
          /* FIXME: Maybe actually realloc to smaller size here? */
924
408k
          break;
925
408k
        }
926
550M
    } while (0);
927
928
550M
  if (memory_resource.memory != 0)
929
261M
    {
930
261M
      (void) memcpy((void *) memory_resource.memory,&memory_resource,
931
261M
                    sizeof(MagickMemoryResource_T));
932
261M
    }
933
550M
  TraceMagickAccessMemoryResource_T(module,function,line,"AFTER",&memory_resource);
934
935
550M
  res = ((status == MagickPass) && memory_resource.memory) ?
936
288M
    UserLandPointerGivenBaseAlloc(memory_resource.memory) : 0;
937
938
550M
  return res;
939
550M
}
940
941
MagickExport void *_MagickReallocateResourceLimitedMemory(void *p,
942
                                                          const size_t count,
943
                                                          const size_t size,
944
                                                          const MagickBool clear)
945
0
{
946
0
  return _MagickReallocateResourceLimitedMemoryLoc(p,count,size,clear,GetMagickModule());
947
0
}
948
949
/*
950
  Allocate resource-limited memory.  Similar to MagickMalloc().
951
952
  Memory must be released using MagickFreeMemoryResource().
953
*/
954
MagickExport void *_MagickAllocateResourceLimitedMemoryLoc(const size_t size,
955
                                                           const char *module,
956
                                                           const char *function,
957
                                                           const unsigned int line)
958
221M
{
959
221M
  return _MagickReallocateResourceLimitedMemoryLoc(0,1,size,MagickFalse,module,function,line);
960
221M
}
961
962
MagickExport void *_MagickAllocateResourceLimitedMemory(const size_t size)
963
0
{
964
0
  return _MagickAllocateResourceLimitedMemoryLoc(size,GetMagickModule());
965
0
}
966
967
/*
968
  Free resource-limited memory which was allocated by
969
  MagickReallocMemoryResource() or MagickMallocMemoryResource().
970
971
  Similar to MagickFree().
972
*/
973
MagickExport void _MagickFreeResourceLimitedMemoryLoc(void *p,
974
    const char *module,const char *function,const unsigned int line)
975
167M
{
976
167M
  _MagickReallocateResourceLimitedMemoryLoc(p,0,0,MagickFalse,module,function,line);
977
167M
}
978
979
MagickExport void _MagickFreeResourceLimitedMemory(void *p)
980
0
{
981
0
  _MagickFreeResourceLimitedMemoryLoc(p,GetMagickModule());
982
0
}
983
984
/*
985
  Get current resource-limited memory size attribute (or defaulted value if NULL)
986
*/
987
MagickExport size_t _MagickResourceLimitedMemoryGetSizeAttribute(const void *p,
988
                                                                 const MagickAllocateResourceLimitedMemoryAttribute attr)
989
0
{
990
0
  MagickMemoryResource_T memory_resource;
991
0
  size_t result = 0;
992
993
  /* Copy (or init) 'memory_resource' based on provided user-land pointer */
994
0
  MagickCopyMemoryResource_T_From_Pub(__FILE__,GetCurrentFunction(),__LINE__,&memory_resource, p);
995
996
0
  switch (attr)
997
0
    {
998
0
    case ResourceLimitedMemoryAttributeAllocSize:
999
      /* Currently requested allocation size */
1000
0
      result = memory_resource.alloc_size;
1001
0
      break;
1002
0
    case ResourceLimitedMemoryAttributeAllocSizeReal:
1003
      /* Actual underlying requested allocation size */
1004
0
      result = memory_resource.alloc_size_real;
1005
0
      break;
1006
0
    case ResourceLimitedMemoryAttributeAllocNumReallocs:
1007
      /* Number of reallocations performed */
1008
0
      result = memory_resource.num_realloc;
1009
0
      break;
1010
0
    case ResourceLimitedMemoryAttributeAllocNumReallocsMoved:
1011
      /* Number of reallocations which moved memory (pointer change) */
1012
0
      result = memory_resource.num_realloc_moves;
1013
0
      break;
1014
0
    case ResourceLimitedMemoryAttributeAllocReallocOctetsMoved:
1015
      /* Total number of octets moved due to reallocations (may overflow!) */
1016
0
      result = memory_resource.realloc_octets_moved;
1017
0
      break;
1018
0
    }
1019
1020
0
  return result;
1021
0
}
1022
1023
/*
1024
  Set a per-allocation resource limit given a pointer to an allocation
1025
*/
1026
MagickExport void _SetMagickResourceLimitedMemoryLimitP(void *p,
1027
                                                        MagickResourceLimitedMemoryLimitType type,
1028
                                                        const size_t limit)
1029
0
{
1030
0
  MagickMemoryResource_T *memory_resource;
1031
1032
0
  memory_resource = MagickAccessMemoryResource_T_From_Pub(p);
1033
1034
0
  switch (type)
1035
0
    {
1036
0
    case MagickResourceLimitedMemoryAllocSizeLimit:
1037
0
      memory_resource->alloc_size_limit=limit;
1038
0
      break;
1039
0
    case MagickResourceLimitedMemoryNumReallocLimit:
1040
0
      memory_resource->num_realloc_limit=limit;
1041
0
      break;
1042
0
    case MagickResourceLimitedMemoryNumReallocMovesLimit:
1043
0
      memory_resource->num_realloc_moves=limit;
1044
0
      break;
1045
0
    }
1046
0
}