Coverage Report

Created: 2026-01-20 07:37

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
806M
{
132
806M
  size_t
133
806M
    allocation_size;
134
135
806M
  allocation_size = size * count;
136
806M
  if ((count != 0) && (size != allocation_size/count))
137
8
    allocation_size = 0;
138
139
806M
  return allocation_size;
140
806M
}
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
218M
{
169
218M
  if (size == 0)
170
0
    return ((void *) NULL);
171
172
  /* fprintf(stderr,"%s %zu\n",__func__, size); */
173
218M
  MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
174
175
218M
  return (MallocFunc)(size);
176
218M
}
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
118M
{
224
118M
  size_t
225
118M
    alligned_size;
226
227
118M
  void
228
118M
    *alligned_p = 0;
229
230
  /* fprintf(stderr,"%s %zu\n",__func__, size); */
231
118M
  MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
232
233
118M
  alligned_size=RoundUpToAlignment(size,alignment);
234
235
118M
  if ((size == 0) || (alignment < sizeof(void *)) || (alligned_size < size))
236
0
    return ((void *) NULL);
237
238
118M
#if defined(HAVE_POSIX_MEMALIGN)
239
118M
  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
118M
  return alligned_p;
265
118M
}
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
19.2M
{
359
19.2M
  size_t
360
19.2M
    allocation_size;
361
362
19.2M
  void
363
19.2M
    *allocation;
364
365
19.2M
  allocation = (void *) NULL;
366
19.2M
  allocation_size=MagickArraySize(count,size);
367
368
19.2M
  if (allocation_size)
369
19.2M
    allocation = MagickMalloc(allocation_size);
370
19.2M
  return allocation;
371
19.2M
}
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
34.7M
{
401
34.7M
  void
402
34.7M
    *p = (void *) NULL;
403
404
34.7M
  if (size != 0)
405
34.7M
    {
406
34.7M
      p=MagickMalloc(size);
407
408
34.7M
      if (p != (void *) NULL)
409
34.7M
        (void) memset(p,0,size);
410
34.7M
    }
411
412
34.7M
  return p;
413
34.7M
}
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.06M
{
497
4.06M
  void
498
4.06M
    *new_memory = (void *) NULL;
499
500
4.06M
  MEMORY_LIMIT_CHECK(GetCurrentFunction(),size);
501
502
4.06M
  if ((void *) NULL == memory)
503
761k
    new_memory = (MallocFunc)(size);
504
3.29M
  else
505
3.29M
    new_memory = (ReallocFunc)(memory,size);
506
4.06M
  if ((new_memory == 0) && (memory != 0) && (size != 0))
507
0
    MagickFree(memory);
508
509
4.06M
  return new_memory;
510
4.06M
}
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.30G
{
540
1.30G
  if (memory != (void *) NULL)
541
706M
    (FreeFunc)(memory);
542
1.30G
}
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
141M
{
574
141M
  if (memory != (void *) NULL)
575
118M
    {
576
118M
#if defined (HAVE_POSIX_MEMALIGN)
577
118M
      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
118M
    }
585
141M
}
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
377M
  ((MagickMemoryResource_T *) ((char *) p-sizeof(MagickMemoryResource_T)))
616
617
/* Return user-land pointer given private base allocation pointer */
618
#define UserLandPointerGivenBaseAlloc(p) \
619
377M
  ((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
781M
  do {                                                                  \
624
781M
    if (p != 0)                                                         \
625
781M
      {                                                                 \
626
377M
        assert(((ptrdiff_t) p - sizeof(MagickMemoryResource_T)) > 0);   \
627
377M
        (void) memcpy(memory_resource,                                  \
628
377M
                      (void *) MagickAccessMemoryResource_T_From_Pub(p), \
629
377M
                      sizeof(MagickMemoryResource_T));                  \
630
377M
        assert((memory_resource)->signature == MagickSignature);        \
631
377M
      }                                                                 \
632
781M
    else                                                                \
633
781M
      {                                                                 \
634
404M
        (memory_resource)->memory = 0;                                  \
635
404M
        (memory_resource)->alloc_size_initial = 0;                      \
636
404M
        (memory_resource)->alloc_size = 0;                              \
637
404M
        (memory_resource)->alloc_size_limit = SIZE_MAX;                 \
638
404M
        (memory_resource)->alloc_size_real = 0;                         \
639
404M
        (memory_resource)->alloc_module = module;                       \
640
404M
        (memory_resource)->alloc_function = function;                   \
641
404M
        (memory_resource)->alloc_line = line;                           \
642
404M
        (memory_resource)->num_realloc = 0;                             \
643
404M
        (memory_resource)->num_realloc_limit = SIZE_MAX;                \
644
404M
        (memory_resource)->num_realloc_moves = 0;                       \
645
404M
        (memory_resource)->num_realloc_moves_limit = SIZE_MAX;          \
646
404M
        (memory_resource)->realloc_octets_moved = 0;                    \
647
404M
        (memory_resource)->signature = MagickSignature;                 \
648
404M
      }                                                                 \
649
781M
  } 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.96G
#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
404M
{
691
404M
  TraceMagickAccessMemoryResource_T(module,function,line,"FREE",memory_resource);
692
404M
#if !(defined(MAGICK_DEBUG_RL_MEMORY) && MAGICK_DEBUG_RL_MEMORY)
693
404M
  (void) module;
694
404M
  (void) function;
695
404M
  (void) line;
696
404M
#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
404M
  if (memory_resource->memory != 0)
735
368M
    {
736
368M
      MagickFree(memory_resource->memory);
737
368M
      memory_resource->memory=0;
738
368M
    }
739
404M
  if (memory_resource->alloc_size != 0)
740
368M
    LiberateMagickResource(MemoryResource, memory_resource->alloc_size);
741
404M
  memory_resource->alloc_size_real = 0;
742
404M
  memory_resource->alloc_size_limit = SIZE_MAX;
743
404M
  memory_resource->alloc_size_initial = 0;
744
404M
  memory_resource->alloc_size = 0;
745
404M
  memory_resource->num_realloc = 0;
746
404M
  memory_resource->num_realloc_limit = SIZE_MAX;
747
404M
  memory_resource->num_realloc_moves = 0;
748
404M
  memory_resource->num_realloc_moves_limit = SIZE_MAX;
749
404M
  memory_resource->realloc_octets_moved = 0;
750
404M
}
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
781M
{
780
781M
  MagickMemoryResource_T memory_resource;
781
781M
  size_t size_diff;
782
781M
  const size_t new_size =  MagickArraySize(count,size);
783
781M
  void *res;
784
781M
  MagickPassFail
785
781M
    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
781M
  MagickCopyMemoryResource_T_From_Pub(module,function,line,&memory_resource, p);
793
781M
  TraceMagickAccessMemoryResource_T(module,function,line,"BEFORE",&memory_resource);
794
795
781M
  do
796
781M
    {
797
781M
      if (((new_size == 0) && (count != 0) && (size != 0)) ||
798
781M
          (new_size > SIZE_MAX/2) ||
799
781M
          (SIZE_MAX-new_size <= sizeof(MagickMemoryResource_T)) ||
800
781M
          (new_size > memory_resource.alloc_size_limit))
801
292
        {
802
          /* Memory allocation FAILED */
803
292
#if defined(ENOMEM)
804
292
          errno = ENOMEM;
805
292
#endif /* if defined(ENOMEM) */
806
292
          status = MagickFail;
807
292
          break;
808
292
        }
809
781M
      else if (new_size == 0)
810
404M
        {
811
          /* Deallocate all allocated memory (if any) */
812
404M
          _MagickFreeResourceLimitedMemory_T(module,function,line,&memory_resource);
813
404M
          break;
814
404M
        }
815
377M
      else if (new_size > memory_resource.alloc_size)
816
373M
        {
817
          /* Allocate or enlarge memory */
818
373M
          size_diff = new_size - memory_resource.alloc_size;
819
373M
          if (AcquireMagickResource(MemoryResource,size_diff) == MagickPass)
820
373M
            {
821
373M
              if (new_size > memory_resource.alloc_size_real)
822
369M
                {
823
369M
                  void *realloc_memory;
824
369M
                  size_t realloc_size = new_size+sizeof(MagickMemoryResource_T);
825
369M
                  if (memory_resource.alloc_size_real != 0)
826
1.35M
                    {
827
                      /* This is a realloc */
828
829
                      /* If number of allocations will exceed reallocation limit */
830
1.35M
                      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.35M
                      else
836
1.35M
                        {
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.35M
                          MagickRoundUpStringLength(realloc_size);
843
1.35M
                        }
844
1.35M
                    }
845
369M
                  realloc_memory = (ReallocFunc)(memory_resource.memory,
846
369M
                                                 realloc_size);
847
                  /* If number of realloc moves exceeds num_realloc_moves_limit */
848
369M
                  if ((realloc_memory != 0) && (memory_resource.alloc_size_real != 0) &&
849
1.35M
                      (realloc_memory != memory_resource.memory))
850
1.08M
                    {
851
1.08M
                      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.08M
                    }
857
369M
                  if ((realloc_memory != 0) && (realloc_size != 0))
858
369M
                    {
859
369M
                      if (clear)
860
497k
                        (void) memset(UserLandPointerGivenBaseAlloc(realloc_memory)+
861
497k
                                      memory_resource.alloc_size,0,size_diff);
862
863
                      /* A realloc has pre-existing memory */
864
369M
                      if (memory_resource.alloc_size_real != 0)
865
1.35M
                        {
866
                          /* Tally actual reallocations */
867
1.35M
                          memory_resource.num_realloc++;
868
                          /* Tally reallocations which resulted in a memory move */
869
1.35M
                          if (realloc_memory != memory_resource.memory)
870
1.08M
                            {
871
1.08M
                              memory_resource.num_realloc_moves++;
872
1.08M
                              memory_resource.realloc_octets_moved +=
873
1.08M
                                memory_resource.alloc_size_real+sizeof(MagickMemoryResource_T);
874
1.08M
                            }
875
1.35M
                        }
876
369M
                      memory_resource.memory = realloc_memory;
877
369M
                      if (memory_resource.alloc_size == 0)
878
368M
                        memory_resource.alloc_size_initial = new_size;
879
369M
                      memory_resource.alloc_size = new_size;
880
369M
                      memory_resource.alloc_size_real = realloc_size-sizeof(MagickMemoryResource_T);
881
369M
                    }
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
369M
                }
891
4.11M
              else
892
4.11M
                {
893
4.11M
                   if (clear)
894
6.02k
                     (void) memset(UserLandPointerGivenBaseAlloc(memory_resource.memory)+
895
6.02k
                                   memory_resource.alloc_size,0,size_diff);
896
897
                  /* Re-allocation is not required */
898
4.11M
                  memory_resource.alloc_size = new_size;
899
4.11M
                }
900
373M
            }
901
763
          else
902
763
            {
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
763
#if defined(ENOMEM)
911
763
              errno = ENOMEM;
912
763
#endif /* if defined(ENOMEM) */
913
763
              status = MagickFail;
914
763
            }
915
373M
          break;
916
373M
        }
917
3.32M
      else if (new_size < memory_resource.alloc_size)
918
484k
        {
919
          /* Reduce memory */
920
484k
          size_diff = memory_resource.alloc_size - new_size;
921
484k
          LiberateMagickResource(MemoryResource,size_diff);
922
484k
          memory_resource.alloc_size = new_size;
923
          /* FIXME: Maybe actually realloc to smaller size here? */
924
484k
          break;
925
484k
        }
926
781M
    } while (0);
927
928
781M
  if (memory_resource.memory != 0)
929
377M
    {
930
377M
      (void) memcpy((void *) memory_resource.memory,&memory_resource,
931
377M
                    sizeof(MagickMemoryResource_T));
932
377M
    }
933
781M
  TraceMagickAccessMemoryResource_T(module,function,line,"AFTER",&memory_resource);
934
935
781M
  res = ((status == MagickPass) && memory_resource.memory) ?
936
404M
    UserLandPointerGivenBaseAlloc(memory_resource.memory) : 0;
937
938
781M
  return res;
939
781M
}
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
333M
{
959
333M
  return _MagickReallocateResourceLimitedMemoryLoc(0,1,size,MagickFalse,module,function,line);
960
333M
}
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
275M
{
976
275M
  _MagickReallocateResourceLimitedMemoryLoc(p,0,0,MagickFalse,module,function,line);
977
275M
}
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
}