Coverage Report

Created: 2026-06-30 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/MagickCore/memory.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                    M   M  EEEEE  M   M   OOO   RRRR   Y   Y                 %
7
%                    MM MM  E      MM MM  O   O  R   R   Y Y                  %
8
%                    M M M  EEE    M M M  O   O  RRRR     Y                   %
9
%                    M   M  E      M   M  O   O  R R      Y                   %
10
%                    M   M  EEEEE  M   M   OOO   R  R     Y                   %
11
%                                                                             %
12
%                                                                             %
13
%                     MagickCore Memory Allocation Methods                    %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1998                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/license/                                         %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%  We provide these memory allocators:
37
%
38
%    AcquireCriticalMemory(): allocate a small memory request with
39
%      AcquireMagickMemory(), however, on fail throw a fatal exception and exit.
40
%      Free the memory reserve with RelinquishMagickMemory().
41
%    AcquireAlignedMemory(): allocate a small memory request that is aligned
42
%      on a cache line.  On fail, return NULL for possible recovery.
43
%      Free the memory reserve with RelinquishMagickMemory().
44
%    AcquireMagickMemory()/ResizeMagickMemory(): allocate a small to medium
45
%      memory request, typically with malloc()/realloc(). On fail, return NULL
46
%      for possible recovery.  Free the memory reserve with
47
%      RelinquishMagickMemory().
48
%    AcquireQuantumMemory()/ResizeQuantumMemory(): allocate a small to medium
49
%      memory request.  This is a secure memory allocator as it accepts two
50
%      parameters, count and quantum, to ensure the request does not overflow.
51
%      It also check to ensure the request does not exceed the maximum memory
52
%      per the security policy.  Free the memory reserve with
53
%      RelinquishMagickMemory().
54
%    AcquireVirtualMemory(): allocate a large memory request either in heap,
55
%      memory-mapped, or memory-mapped on disk depending on whether heap
56
%      allocation fails or if the request exceeds the maximum memory policy.
57
%      Free the memory reserve with RelinquishVirtualMemory().
58
%    ResetMagickMemory(): fills the bytes of the memory area with a constant
59
%      byte.
60
%    
61
%  In addition, we provide hooks for your own memory constructor/destructors.
62
%  You can also utilize our internal custom allocator as follows: Segregate
63
%  our memory requirements from any program that calls our API.  This should
64
%  help reduce the risk of others changing our program state or causing memory
65
%  corruption.
66
%
67
%  Our custom memory allocation manager implements a best-fit allocation policy
68
%  using segregated free lists.  It uses a linear distribution of size classes
69
%  for lower sizes and a power of two distribution of size classes at higher
70
%  sizes.  It is based on the paper, "Fast Memory Allocation using Lazy Fits."
71
%  written by Yoo C. Chung.
72
%
73
%  By default, C's standard library is used (e.g. malloc);  use the
74
%  custom memory allocator by defining MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT
75
%  to allocate memory with private anonymous mapping rather than from the
76
%  heap.
77
%
78
*/
79

80
/*
81
  Include declarations.
82
*/
83
#include "MagickCore/studio.h"
84
#include "MagickCore/blob.h"
85
#include "MagickCore/blob-private.h"
86
#include "MagickCore/exception.h"
87
#include "MagickCore/exception-private.h"
88
#include "MagickCore/image-private.h"
89
#include "MagickCore/memory_.h"
90
#include "MagickCore/memory-private.h"
91
#include "MagickCore/policy.h"
92
#include "MagickCore/resource_.h"
93
#include "MagickCore/semaphore.h"
94
#include "MagickCore/string_.h"
95
#include "MagickCore/string-private.h"
96
#include "MagickCore/utility-private.h"
97

98
/*
99
  Define declarations.
100
*/
101
#define BlockFooter(block,size) \
102
  ((size_t *) ((char *) (block)+(size)-2*sizeof(size_t)))
103
#define BlockHeader(block)  ((size_t *) (block)-1)
104
#define BlockThreshold  1024
105
#define MaxBlockExponent  16
106
#define MaxBlocks ((BlockThreshold/(4*sizeof(size_t)))+MaxBlockExponent+1)
107
#define MaxSegments  1024
108
#define NextBlock(block)  ((char *) (block)+SizeOfBlock(block))
109
#define NextBlockInList(block)  (*(void **) (block))
110
#define PreviousBlock(block)  ((char *) (block)-(*((size_t *) (block)-2)))
111
#define PreviousBlockBit  0x01
112
#define PreviousBlockInList(block)  (*((void **) (block)+1))
113
#define SegmentSize  (2*1024*1024)
114
#define SizeMask  (~0x01)
115
#define SizeOfBlock(block)  (*BlockHeader(block) & SizeMask)
116

117
/*
118
  Typedef declarations.
119
*/
120
typedef enum
121
{
122
  UndefinedVirtualMemory,
123
  AlignedVirtualMemory,
124
  MapVirtualMemory,
125
  UnalignedVirtualMemory
126
} VirtualMemoryType;
127
128
typedef struct _DataSegmentInfo
129
{
130
  void
131
    *allocation,
132
    *bound;
133
134
  MagickBooleanType
135
    mapped;
136
137
  size_t
138
    length;
139
140
  struct _DataSegmentInfo
141
    *previous,
142
    *next;
143
} DataSegmentInfo;
144
145
typedef struct _MagickMemoryMethods
146
{
147
  AcquireMemoryHandler
148
    acquire_memory_handler;
149
150
  ResizeMemoryHandler
151
    resize_memory_handler;
152
153
  DestroyMemoryHandler
154
    destroy_memory_handler;
155
156
  AcquireAlignedMemoryHandler
157
    acquire_aligned_memory_handler;
158
159
  RelinquishAlignedMemoryHandler
160
    relinquish_aligned_memory_handler;
161
} MagickMemoryMethods;
162
163
struct _MemoryInfo
164
{
165
  char
166
    filename[MagickPathExtent];
167
168
  VirtualMemoryType
169
    type;
170
171
  size_t
172
    length;
173
174
  void
175
    *blob;
176
177
  size_t
178
    signature;
179
};
180
181
typedef struct _MemoryPool
182
{
183
  size_t
184
    allocation;
185
186
  void
187
    *blocks[MaxBlocks+1];
188
189
  size_t
190
    number_segments;
191
192
  DataSegmentInfo
193
    *segments[MaxSegments],
194
    segment_pool[MaxSegments];
195
} MemoryPool;
196

197
/*
198
  Global declarations.
199
*/
200
static size_t
201
  max_memory_request = 0,
202
  max_profile_size = 0,
203
  virtual_anonymous_memory = 0;
204
205
static MagickMemoryMethods
206
  memory_methods =
207
  {
208
    (AcquireMemoryHandler) malloc,
209
    (ResizeMemoryHandler) realloc,
210
    (DestroyMemoryHandler) free,
211
    (AcquireAlignedMemoryHandler) NULL,
212
    (RelinquishAlignedMemoryHandler) NULL
213
  };
214
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
215
static MemoryPool
216
  memory_pool;
217
218
static SemaphoreInfo
219
  *memory_semaphore = (SemaphoreInfo *) NULL;
220
221
static volatile DataSegmentInfo
222
  *free_segments = (DataSegmentInfo *) NULL;
223

224
/*
225
  Forward declarations.
226
*/
227
static MagickBooleanType
228
  ExpandHeap(size_t);
229
#endif
230

231
/*
232
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233
%                                                                             %
234
%                                                                             %
235
%                                                                             %
236
%   A c q u i r e A l i g n e d M e m o r y                                   %
237
%                                                                             %
238
%                                                                             %
239
%                                                                             %
240
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241
%
242
%  AcquireAlignedMemory() returns a pointer to a block of memory whose size is
243
%  at least (count*quantum) bytes, and whose address is aligned on a cache line.
244
%
245
%  The format of the AcquireAlignedMemory method is:
246
%
247
%      void *AcquireAlignedMemory(const size_t count,const size_t quantum)
248
%
249
%  A description of each parameter follows:
250
%
251
%    o count: the number of objects to allocate contiguously.
252
%
253
%    o quantum: the size (in bytes) of each object.
254
%
255
*/
256
#if defined(MAGICKCORE_HAVE_ALIGNED_MALLOC)
257
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_STDC
258
static inline void *AcquireAlignedMemory_STDC(const size_t size)
259
{
260
  size_t
261
    extent = CACHE_ALIGNED(size);
262
263
  if (extent < size)
264
    {
265
      errno=ENOMEM;
266
      return(NULL);
267
    }
268
  return(aligned_alloc(CACHE_LINE_SIZE,extent));
269
}
270
#elif defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
271
23.5M
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_POSIX
272
static inline void *AcquireAlignedMemory_POSIX(const size_t size)
273
23.5M
{
274
23.5M
  void
275
23.5M
    *memory;
276
277
23.5M
  if (posix_memalign(&memory,CACHE_LINE_SIZE,size))
278
0
    return(NULL);
279
23.5M
  return(memory);
280
23.5M
}
281
#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
282
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_WinAPI
283
static inline void *AcquireAlignedMemory_WinAPI(const size_t size)
284
{
285
  return(_aligned_malloc(size,CACHE_LINE_SIZE));
286
}
287
#else
288
#define ALIGNMENT_OVERHEAD \
289
  (MAGICKCORE_MAX_ALIGNMENT_PADDING(CACHE_LINE_SIZE) + MAGICKCORE_SIZEOF_VOID_P)
290
static inline void *reserve_space_for_actual_base_address(void *const p)
291
{
292
  return((void **) p+1);
293
}
294
295
static inline void **pointer_to_space_for_actual_base_address(void *const p)
296
{
297
  return((void **) p-1);
298
}
299
300
static inline void *actual_base_address(void *const p)
301
{
302
  return(*pointer_to_space_for_actual_base_address(p));
303
}
304
305
static inline void *align_to_cache(void *const p)
306
{
307
  return((void *) CACHE_ALIGNED((MagickAddressType) p));
308
}
309
310
static inline void *adjust(void *const p)
311
{
312
  return(align_to_cache(reserve_space_for_actual_base_address(p)));
313
}
314
315
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_Generic
316
static inline void *AcquireAlignedMemory_Generic(const size_t size)
317
{
318
  size_t
319
    extent;
320
321
  void
322
    *memory,
323
    *p;
324
325
  #if SIZE_MAX < ALIGNMENT_OVERHEAD
326
    #error "CACHE_LINE_SIZE is way too big."
327
  #endif
328
  extent=(size+ALIGNMENT_OVERHEAD);
329
  if (extent <= size)
330
    {
331
      errno=ENOMEM;
332
      return(NULL);
333
    }
334
  p=AcquireMagickMemory(extent);
335
  if (p == NULL)
336
    return(NULL);
337
  memory=adjust(p);
338
  *pointer_to_space_for_actual_base_address(memory)=p;
339
  return(memory);
340
}
341
#endif
342
343
MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum)
344
23.5M
{
345
23.5M
  size_t
346
23.5M
    size;
347
348
23.5M
  if ((HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse) ||
349
23.5M
      (size > GetMaxMemoryRequest()))
350
37
    {
351
37
      errno=ENOMEM;
352
37
      return(NULL);
353
37
    }
354
23.5M
  if (memory_methods.acquire_aligned_memory_handler != (AcquireAlignedMemoryHandler) NULL)
355
0
    return(memory_methods.acquire_aligned_memory_handler(size,CACHE_LINE_SIZE));
356
23.5M
  return(AcquireAlignedMemory_Actual(size));
357
23.5M
}
358

359
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
360
/*
361
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362
%                                                                             %
363
%                                                                             %
364
%                                                                             %
365
+   A c q u i r e B l o c k                                                   %
366
%                                                                             %
367
%                                                                             %
368
%                                                                             %
369
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370
%
371
%  AcquireBlock() returns a pointer to a block of memory at least size bytes
372
%  suitably aligned for any use.
373
%
374
%  The format of the AcquireBlock method is:
375
%
376
%      void *AcquireBlock(const size_t size)
377
%
378
%  A description of each parameter follows:
379
%
380
%    o size: the size of the memory in bytes to allocate.
381
%
382
*/
383
384
static inline size_t AllocationPolicy(size_t size)
385
{
386
  size_t
387
    blocksize;
388
389
  /*
390
    The linear distribution.
391
  */
392
  assert(size != 0);
393
  assert(size % (4*sizeof(size_t)) == 0);
394
  if (size <= BlockThreshold)
395
    return(size/(4*sizeof(size_t)));
396
  /*
397
    Check for the largest block size.
398
  */
399
  if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L))))
400
    return(MaxBlocks-1L);
401
  /*
402
    Otherwise use a power of two distribution.
403
  */
404
  blocksize=BlockThreshold/(4*sizeof(size_t));
405
  for ( ; size > BlockThreshold; size/=2)
406
    blocksize++;
407
  assert(blocksize > (BlockThreshold/(4*sizeof(size_t))));
408
  assert(blocksize < (MaxBlocks-1L));
409
  return(blocksize);
410
}
411
412
static inline void InsertFreeBlock(void *block,const size_t i)
413
{
414
  void
415
    *next,
416
    *previous;
417
418
  size_t
419
    size;
420
421
  size=SizeOfBlock(block);
422
  previous=(void *) NULL;
423
  next=memory_pool.blocks[i];
424
  while ((next != (void *) NULL) && (SizeOfBlock(next) < size))
425
  {
426
    previous=next;
427
    next=NextBlockInList(next);
428
  }
429
  PreviousBlockInList(block)=previous;
430
  NextBlockInList(block)=next;
431
  if (previous != (void *) NULL)
432
    NextBlockInList(previous)=block;
433
  else
434
    memory_pool.blocks[i]=block;
435
  if (next != (void *) NULL)
436
    PreviousBlockInList(next)=block;
437
}
438
439
static inline void RemoveFreeBlock(void *block,const size_t i)
440
{
441
  void
442
    *next,
443
    *previous;
444
445
  next=NextBlockInList(block);
446
  previous=PreviousBlockInList(block);
447
  if (previous == (void *) NULL)
448
    memory_pool.blocks[i]=next;
449
  else
450
    NextBlockInList(previous)=next;
451
  if (next != (void *) NULL)
452
    PreviousBlockInList(next)=previous;
453
}
454
455
static void *AcquireBlock(size_t size)
456
{
457
  size_t
458
    i;
459
460
  void
461
    *block;
462
463
  /*
464
    Find free block.
465
  */
466
  size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t));
467
  i=AllocationPolicy(size);
468
  block=memory_pool.blocks[i];
469
  while ((block != (void *) NULL) && (SizeOfBlock(block) < size))
470
    block=NextBlockInList(block);
471
  if (block == (void *) NULL)
472
    {
473
      i++;
474
      while (memory_pool.blocks[i] == (void *) NULL)
475
        i++;
476
      block=memory_pool.blocks[i];
477
      if (i >= MaxBlocks)
478
        return((void *) NULL);
479
    }
480
  assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0);
481
  assert(SizeOfBlock(block) >= size);
482
  RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block)));
483
  if (SizeOfBlock(block) > size)
484
    {
485
      size_t
486
        blocksize;
487
488
      void
489
        *next;
490
491
      /*
492
        Split block.
493
      */
494
      next=(char *) block+size;
495
      blocksize=SizeOfBlock(block)-size;
496
      *BlockHeader(next)=blocksize;
497
      *BlockFooter(next,blocksize)=blocksize;
498
      InsertFreeBlock(next,AllocationPolicy(blocksize));
499
      *BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask);
500
    }
501
  assert(size == SizeOfBlock(block));
502
  *BlockHeader(NextBlock(block))|=PreviousBlockBit;
503
  memory_pool.allocation+=size;
504
  return(block);
505
}
506
#endif
507

508
/*
509
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
510
%                                                                             %
511
%                                                                             %
512
%                                                                             %
513
%   A c q u i r e M a g i c k M e m o r y                                     %
514
%                                                                             %
515
%                                                                             %
516
%                                                                             %
517
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518
%
519
%  AcquireMagickMemory() returns a pointer to a block of memory at least size
520
%  bytes suitably aligned for any use.
521
%
522
%  The format of the AcquireMagickMemory method is:
523
%
524
%      void *AcquireMagickMemory(const size_t size)
525
%
526
%  A description of each parameter follows:
527
%
528
%    o size: the size of the memory in bytes to allocate.
529
%
530
*/
531
MagickExport void *AcquireMagickMemory(const size_t size)
532
692M
{
533
692M
  void
534
692M
    *memory;
535
536
692M
#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
537
692M
  memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
538
#else
539
  if (memory_semaphore == (SemaphoreInfo *) NULL)
540
    ActivateSemaphoreInfo(&memory_semaphore);
541
  if (free_segments == (DataSegmentInfo *) NULL)
542
    {
543
      LockSemaphoreInfo(memory_semaphore);
544
      if (free_segments == (DataSegmentInfo *) NULL)
545
        {
546
          ssize_t
547
            i;
548
549
          assert(2*sizeof(size_t) > (size_t) (~SizeMask));
550
          (void) memset(&memory_pool,0,sizeof(memory_pool));
551
          memory_pool.allocation=SegmentSize;
552
          memory_pool.blocks[MaxBlocks]=(void *) (-1);
553
          for (i=0; i < MaxSegments; i++)
554
          {
555
            if (i != 0)
556
              memory_pool.segment_pool[i].previous=
557
                (&memory_pool.segment_pool[i-1]);
558
            if (i != (MaxSegments-1))
559
              memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]);
560
          }
561
          free_segments=(&memory_pool.segment_pool[0]);
562
        }
563
      UnlockSemaphoreInfo(memory_semaphore);
564
    }
565
  LockSemaphoreInfo(memory_semaphore);
566
  memory=AcquireBlock(size == 0 ? 1UL : size);
567
  if (memory == (void *) NULL)
568
    {
569
      if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse)
570
        memory=AcquireBlock(size == 0 ? 1UL : size);
571
    }
572
  UnlockSemaphoreInfo(memory_semaphore);
573
#endif
574
692M
  return(memory);
575
692M
}
576

577
/*
578
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
579
%                                                                             %
580
%                                                                             %
581
%                                                                             %
582
%   A c q u i r e C r i t i c a l M e m o r y                                 %
583
%                                                                             %
584
%                                                                             %
585
%                                                                             %
586
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
587
%
588
%  AcquireCriticalMemory() is just like AcquireMagickMemory(), throws a fatal
589
%  exception if the memory cannot be acquired.
590
%
591
%  That is, AcquireCriticalMemory() returns a pointer to a block of memory that
592
%  is at least size bytes, and that is suitably aligned for any use; however,
593
%  if this is not possible, it throws an exception and terminates the program
594
%  as unceremoniously as possible.
595
%
596
%  The format of the AcquireCriticalMemory method is:
597
%
598
%      void *AcquireCriticalMemory(const size_t size)
599
%
600
%  A description of each parameter follows:
601
%
602
%    o size: the size (in bytes) of the memory to allocate.
603
%
604
*/
605
MagickExport void *AcquireCriticalMemory(const size_t size)
606
214M
{
607
#if !defined(STDERR_FILENO)
608
#define STDERR_FILENO 2
609
#endif
610
611
214M
  int
612
214M
    status;
613
614
214M
  static const char fatal_message[] =
615
214M
    "ImageMagick: fatal error: unable to acquire critical memory\n";
616
617
214M
  void
618
214M
    *memory;
619
620
  /*
621
    Fail if memory request cannot be fulfilled.
622
  */
623
214M
  memory=AcquireMagickMemory(size);
624
214M
  if (memory != (void *) NULL)
625
214M
    return(memory);
626
0
  status=write(STDERR_FILENO,fatal_message,sizeof(fatal_message)-1);
627
0
  (void) status;
628
0
  MagickCoreTerminus();
629
0
  _exit(EXIT_FAILURE);
630
214M
}
631

632
/*
633
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634
%                                                                             %
635
%                                                                             %
636
%                                                                             %
637
%   A c q u i r e Q u a n t u m M e m o r y                                   %
638
%                                                                             %
639
%                                                                             %
640
%                                                                             %
641
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642
%
643
%  AcquireQuantumMemory() returns a pointer to a block of memory at least
644
%  count * quantum bytes suitably aligned for any use.
645
%
646
%  The format of the AcquireQuantumMemory method is:
647
%
648
%      void *AcquireQuantumMemory(const size_t count,const size_t quantum)
649
%
650
%  A description of each parameter follows:
651
%
652
%    o count: the number of objects to allocate contiguously.
653
%
654
%    o quantum: the size (in bytes) of each object.
655
%
656
*/
657
MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
658
387M
{
659
387M
  size_t
660
387M
    size;
661
662
387M
  if ((HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse) ||
663
387M
      (size > GetMaxMemoryRequest()))
664
1.21k
    {
665
1.21k
      errno=ENOMEM;
666
1.21k
      return(NULL);
667
1.21k
    }
668
387M
  return(AcquireMagickMemory(size));
669
387M
}
670

671
/*
672
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
673
%                                                                             %
674
%                                                                             %
675
%                                                                             %
676
%   A c q u i r e V i r t u a l M e m o r y                                   %
677
%                                                                             %
678
%                                                                             %
679
%                                                                             %
680
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
681
%
682
%  AcquireVirtualMemory() allocates a pointer to a block of memory at least
683
%  size bytes suitably aligned for any use. In addition to heap, it also
684
%  supports memory-mapped and file-based memory-mapped memory requests.
685
%
686
%  The format of the AcquireVirtualMemory method is:
687
%
688
%      MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum)
689
%
690
%  A description of each parameter follows:
691
%
692
%    o count: the number of objects to allocate contiguously.
693
%
694
%    o quantum: the size (in bytes) of each object.
695
%
696
*/
697
MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
698
  const size_t quantum)
699
502k
{
700
502k
  char
701
502k
    *value;
702
703
502k
  MemoryInfo
704
502k
    *memory_info;
705
706
502k
  size_t
707
502k
    size;
708
709
502k
  if (HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse)
710
18
    {
711
18
      errno=ENOMEM;
712
18
      return((MemoryInfo *) NULL);
713
18
    }
714
502k
  if (virtual_anonymous_memory == 0)
715
68
    {
716
68
      virtual_anonymous_memory=1;
717
68
      value=GetPolicyValue("system:memory-map");
718
68
      if (LocaleCompare(value,"anonymous") == 0)
719
0
        {
720
          /*
721
            The security policy sets anonymous mapping for the memory request.
722
          */
723
0
#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
724
0
          virtual_anonymous_memory=2;
725
0
#endif
726
0
        }
727
68
      value=DestroyString(value);
728
68
    }
729
502k
  memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
730
502k
    sizeof(*memory_info)));
731
502k
  if (memory_info == (MemoryInfo *) NULL)
732
502k
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
733
502k
  (void) memset(memory_info,0,sizeof(*memory_info));
734
502k
  memory_info->length=size;
735
502k
  memory_info->signature=MagickCoreSignature;
736
502k
  if ((virtual_anonymous_memory == 1) && (size <= GetMaxMemoryRequest()))
737
498k
    {
738
498k
      memory_info->blob=AcquireAlignedMemory(1,size);
739
498k
      if (memory_info->blob != NULL)
740
498k
        memory_info->type=AlignedVirtualMemory;
741
498k
    }
742
502k
  if (memory_info->blob == NULL)
743
3.49k
    {
744
      /*
745
        Acquire anonymous memory map.
746
      */
747
3.49k
      memory_info->blob=NULL;
748
3.49k
      if (size <= GetMaxMemoryRequest())
749
0
        memory_info->blob=MapBlob(-1,IOMode,0,size);
750
3.49k
      if (memory_info->blob != NULL)
751
0
        memory_info->type=MapVirtualMemory;
752
3.49k
      else
753
3.49k
        {
754
3.49k
          int
755
3.49k
            file;
756
757
          /*
758
            Anonymous memory mapping failed, try file-backed memory mapping.
759
          */
760
3.49k
          file=AcquireUniqueFileResource(memory_info->filename);
761
3.49k
          if (file != -1)
762
3.49k
            {
763
3.49k
              MagickOffsetType
764
3.49k
                offset;
765
766
3.49k
              offset=(MagickOffsetType) lseek(file,(off_t) (size-1),SEEK_SET);
767
3.49k
              if ((offset == (MagickOffsetType) (size-1)) &&
768
3.49k
                  (write(file,"",1) == 1))
769
3.49k
                {
770
#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
771
                  memory_info->blob=MapBlob(file,IOMode,0,size);
772
#else
773
3.49k
                  if (posix_fallocate(file,0,(MagickOffsetType) size) == 0)
774
3.49k
                    memory_info->blob=MapBlob(file,IOMode,0,size);
775
3.49k
#endif
776
3.49k
                  if (memory_info->blob != NULL)
777
3.49k
                    memory_info->type=MapVirtualMemory;
778
0
                  else
779
0
                    {
780
0
                      (void) RelinquishUniqueFileResource(
781
0
                        memory_info->filename);
782
0
                      *memory_info->filename='\0';
783
0
                    }
784
3.49k
                }
785
3.49k
              (void) close_utf8(file);
786
3.49k
            }
787
3.49k
        }
788
3.49k
    }
789
502k
  if (memory_info->blob == NULL)
790
0
    {
791
0
      memory_info->blob=AcquireQuantumMemory(1,size);
792
0
      if (memory_info->blob != NULL)
793
0
        memory_info->type=UnalignedVirtualMemory;
794
0
    }
795
502k
  if (memory_info->blob == NULL)
796
0
    memory_info=RelinquishVirtualMemory(memory_info);
797
502k
  return(memory_info);
798
502k
}
799

800
/*
801
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802
%                                                                             %
803
%                                                                             %
804
%                                                                             %
805
%   C o p y M a g i c k M e m o r y                                           %
806
%                                                                             %
807
%                                                                             %
808
%                                                                             %
809
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810
%
811
%  CopyMagickMemory() copies size bytes from memory area source to the
812
%  destination.  Copying between objects that overlap will take place
813
%  correctly.  It returns destination.
814
%
815
%  The format of the CopyMagickMemory method is:
816
%
817
%      void *CopyMagickMemory(void *magick_restrict destination,
818
%        const void *magick_restrict source,const size_t size)
819
%
820
%  A description of each parameter follows:
821
%
822
%    o destination: the destination.
823
%
824
%    o source: the source.
825
%
826
%    o size: the size of the memory in bytes to allocate.
827
%
828
*/
829
MagickExport void *CopyMagickMemory(void *magick_restrict destination,
830
  const void *magick_restrict source,const size_t size)
831
28.0k
{
832
28.0k
  const unsigned char
833
28.0k
    *p;
834
835
28.0k
  unsigned char
836
28.0k
    *q;
837
838
28.0k
  assert(destination != (void *) NULL);
839
28.0k
  assert(source != (const void *) NULL);
840
28.0k
  p=(const unsigned char *) source;
841
28.0k
  q=(unsigned char *) destination;
842
28.0k
  if (((q+size) < p) || (q > (p+size)))
843
28.0k
    switch (size)
844
28.0k
    {
845
11.6k
      default: return(memcpy(destination,source,size));
846
3.08k
      case 8: *q++=(*p++); magick_fallthrough;
847
9.63k
      case 7: *q++=(*p++); magick_fallthrough;
848
16.3k
      case 6: *q++=(*p++); magick_fallthrough;
849
16.3k
      case 5: *q++=(*p++); magick_fallthrough;
850
16.3k
      case 4: *q++=(*p++); magick_fallthrough;
851
16.3k
      case 3: *q++=(*p++); magick_fallthrough;
852
16.3k
      case 2: *q++=(*p++); magick_fallthrough;
853
16.3k
      case 1: *q++=(*p++); magick_fallthrough;
854
16.3k
      case 0: return(destination);
855
28.0k
    }
856
0
  return(memmove(destination,source,size));
857
28.0k
}
858

859
/*
860
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
861
%                                                                             %
862
%                                                                             %
863
%                                                                             %
864
+   D e s t r o y M a g i c k M e m o r y                                     %
865
%                                                                             %
866
%                                                                             %
867
%                                                                             %
868
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
869
%
870
%  DestroyMagickMemory() deallocates memory associated with the memory manager.
871
%
872
%  The format of the DestroyMagickMemory method is:
873
%
874
%      DestroyMagickMemory(void)
875
%
876
*/
877
MagickExport void DestroyMagickMemory(void)
878
0
{
879
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
880
  ssize_t
881
    i;
882
883
  if (memory_semaphore == (SemaphoreInfo *) NULL)
884
    ActivateSemaphoreInfo(&memory_semaphore);
885
  LockSemaphoreInfo(memory_semaphore);
886
  for (i=0; i < (ssize_t) memory_pool.number_segments; i++)
887
    if (memory_pool.segments[i]->mapped == MagickFalse)
888
      memory_methods.destroy_memory_handler(
889
        memory_pool.segments[i]->allocation);
890
    else
891
      (void) UnmapBlob(memory_pool.segments[i]->allocation,
892
        memory_pool.segments[i]->length);
893
  free_segments=(DataSegmentInfo *) NULL;
894
  (void) memset(&memory_pool,0,sizeof(memory_pool));
895
  UnlockSemaphoreInfo(memory_semaphore);
896
  RelinquishSemaphoreInfo(&memory_semaphore);
897
#endif
898
0
}
899

900
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
901
/*
902
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
903
%                                                                             %
904
%                                                                             %
905
%                                                                             %
906
+   E x p a n d H e a p                                                       %
907
%                                                                             %
908
%                                                                             %
909
%                                                                             %
910
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911
%
912
%  ExpandHeap() get more memory from the system.  It returns MagickTrue on
913
%  success otherwise MagickFalse.
914
%
915
%  The format of the ExpandHeap method is:
916
%
917
%      MagickBooleanType ExpandHeap(size_t size)
918
%
919
%  A description of each parameter follows:
920
%
921
%    o size: the size of the memory in bytes we require.
922
%
923
*/
924
static MagickBooleanType ExpandHeap(size_t size)
925
{
926
  DataSegmentInfo
927
    *segment_info;
928
929
  MagickBooleanType
930
    mapped;
931
932
  ssize_t
933
    i;
934
935
  void
936
    *block;
937
938
  size_t
939
    blocksize;
940
941
  void
942
    *segment;
943
944
  blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
945
  assert(memory_pool.number_segments < MaxSegments);
946
  segment=MapBlob(-1,IOMode,0,blocksize);
947
  mapped=segment != (void *) NULL ? MagickTrue : MagickFalse;
948
  if (segment == (void *) NULL)
949
    segment=(void *) memory_methods.acquire_memory_handler(blocksize);
950
  if (segment == (void *) NULL)
951
    return(MagickFalse);
952
  segment_info=(DataSegmentInfo *) free_segments;
953
  free_segments=segment_info->next;
954
  segment_info->mapped=mapped;
955
  segment_info->length=blocksize;
956
  segment_info->allocation=segment;
957
  segment_info->bound=(char *) segment+blocksize;
958
  i=(ssize_t) memory_pool.number_segments-1;
959
  for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--)
960
    memory_pool.segments[i+1]=memory_pool.segments[i];
961
  memory_pool.segments[i+1]=segment_info;
962
  memory_pool.number_segments++;
963
  size=blocksize-12*sizeof(size_t);
964
  block=(char *) segment_info->allocation+4*sizeof(size_t);
965
  *BlockHeader(block)=size | PreviousBlockBit;
966
  *BlockFooter(block,size)=size;
967
  InsertFreeBlock(block,AllocationPolicy(size));
968
  block=NextBlock(block);
969
  assert(block < segment_info->bound);
970
  *BlockHeader(block)=2*sizeof(size_t);
971
  *BlockHeader(NextBlock(block))=PreviousBlockBit;
972
  return(MagickTrue);
973
}
974
#endif
975

976
/*
977
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978
%                                                                             %
979
%                                                                             %
980
%                                                                             %
981
%   G e t M a g i c k M e m o r y M e t h o d s                               %
982
%                                                                             %
983
%                                                                             %
984
%                                                                             %
985
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986
%
987
%  GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy
988
%  memory.
989
%
990
%  The format of the GetMagickMemoryMethods() method is:
991
%
992
%      void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler,
993
%        ResizeMemoryHandler *resize_memory_handler,
994
%        DestroyMemoryHandler *destroy_memory_handler)
995
%
996
%  A description of each parameter follows:
997
%
998
%    o acquire_memory_handler: method to acquire memory (e.g. malloc).
999
%
1000
%    o resize_memory_handler: method to resize memory (e.g. realloc).
1001
%
1002
%    o destroy_memory_handler: method to destroy memory (e.g. free).
1003
%
1004
*/
1005
MagickExport void GetMagickMemoryMethods(
1006
  AcquireMemoryHandler *acquire_memory_handler,
1007
  ResizeMemoryHandler *resize_memory_handler,
1008
  DestroyMemoryHandler *destroy_memory_handler)
1009
0
{
1010
0
  assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL);
1011
0
  assert(resize_memory_handler != (ResizeMemoryHandler *) NULL);
1012
0
  assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL);
1013
0
  *acquire_memory_handler=memory_methods.acquire_memory_handler;
1014
0
  *resize_memory_handler=memory_methods.resize_memory_handler;
1015
0
  *destroy_memory_handler=memory_methods.destroy_memory_handler;
1016
0
}
1017

1018
/*
1019
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020
%                                                                             %
1021
%                                                                             %
1022
%                                                                             %
1023
+   G e t M a x M e m o r y R e q u e s t                                     %
1024
%                                                                             %
1025
%                                                                             %
1026
%                                                                             %
1027
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028
%
1029
%  GetMaxMemoryRequest() returns the max memory request value.
1030
%
1031
%  The format of the GetMaxMemoryRequest method is:
1032
%
1033
%      size_t GetMaxMemoryRequest(void)
1034
%
1035
*/
1036
static size_t GetMaxMemoryRequestFromPolicy(void)
1037
590
{
1038
590
#define MinMemoryRequest "16MiB"
1039
1040
590
  char
1041
590
    *value;
1042
1043
590
  size_t
1044
590
    max_memory = (size_t) MAGICK_SSIZE_MAX;
1045
1046
590
  value=GetPolicyValue("system:max-memory-request");
1047
590
  if (value != (char *) NULL)
1048
0
    {
1049
      /*
1050
        The security policy sets a max memory request limit.
1051
      */
1052
0
      max_memory=MagickMax(StringToSizeType(value,100.0),StringToSizeType(
1053
0
        MinMemoryRequest,100.0));
1054
0
      value=DestroyString(value);
1055
0
    }
1056
590
  return(MagickMin(max_memory,(size_t) MAGICK_SSIZE_MAX));
1057
590
}
1058
1059
MagickExport size_t GetMaxMemoryRequest(void)
1060
487M
{
1061
487M
  if (max_memory_request == 0)
1062
295
    {
1063
      /*
1064
        Setting this to unlimited before we check the policy value to avoid
1065
        recursive calls to GetMaxMemoryRequestFromPolicy()
1066
      */
1067
295
      max_memory_request=(size_t) MAGICK_SSIZE_MAX;
1068
295
      max_memory_request=GetMaxMemoryRequestFromPolicy();
1069
295
    } 
1070
487M
  return(max_memory_request);
1071
487M
}
1072

1073
/*
1074
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1075
%                                                                             %
1076
%                                                                             %
1077
%                                                                             %
1078
+   G e t M a x P r o f i l e S i z e                                         %
1079
%                                                                             %
1080
%                                                                             %
1081
%                                                                             %
1082
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083
%
1084
%  GetMaxProfileSize() returns the max profile size value.
1085
%
1086
%  The format of the GetMaxMemoryRequest method is:
1087
%
1088
%      size_t GetMaxProfileSize(void)
1089
%
1090
*/
1091
static size_t GetMaxProfileSizeFromPolicy(void)
1092
295
{
1093
295
  char
1094
295
    *value;
1095
1096
295
  size_t
1097
295
    max=(size_t) MAGICK_SSIZE_MAX;
1098
1099
295
  value=GetPolicyValue("system:max-profile-size");
1100
295
  if (value != (char *) NULL)
1101
0
    {
1102
      /*
1103
        The security policy sets a max profile size limit.
1104
      */
1105
0
      max=StringToSizeType(value,100.0);
1106
0
      value=DestroyString(value);
1107
0
    }
1108
295
  return(MagickMin(max,(size_t) MAGICK_SSIZE_MAX));
1109
295
}
1110
1111
MagickExport size_t GetMaxProfileSize(void)
1112
646k
{
1113
646k
  if (max_profile_size == 0)
1114
0
    max_profile_size=GetMaxProfileSizeFromPolicy();
1115
646k
  return(max_profile_size);
1116
646k
}
1117

1118
/*
1119
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120
%                                                                             %
1121
%                                                                             %
1122
%                                                                             %
1123
%   G e t V i r t u a l M e m o r y B l o b                                   %
1124
%                                                                             %
1125
%                                                                             %
1126
%                                                                             %
1127
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128
%
1129
%  GetVirtualMemoryBlob() returns the virtual memory blob associated with the
1130
%  specified MemoryInfo structure.
1131
%
1132
%  The format of the GetVirtualMemoryBlob method is:
1133
%
1134
%      void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
1135
%
1136
%  A description of each parameter follows:
1137
%
1138
%    o memory_info: The MemoryInfo structure.
1139
*/
1140
MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
1141
814k
{
1142
814k
  assert(memory_info != (const MemoryInfo *) NULL);
1143
814k
  assert(memory_info->signature == MagickCoreSignature);
1144
814k
  return(memory_info->blob);
1145
814k
}
1146

1147
/*
1148
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149
%                                                                             %
1150
%                                                                             %
1151
%                                                                             %
1152
%   R e l i n q u i s h A l i g n e d M e m o r y                             %
1153
%                                                                             %
1154
%                                                                             %
1155
%                                                                             %
1156
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1157
%
1158
%  RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory()
1159
%  or reuse.
1160
%
1161
%  The format of the RelinquishAlignedMemory method is:
1162
%
1163
%      void *RelinquishAlignedMemory(void *memory)
1164
%
1165
%  A description of each parameter follows:
1166
%
1167
%    o memory: A pointer to a block of memory to free for reuse.
1168
%
1169
*/
1170
MagickExport void *RelinquishAlignedMemory(void *memory)
1171
23.5M
{
1172
23.5M
  if (memory == (void *) NULL)
1173
0
    return((void *) NULL);
1174
23.5M
  if (memory_methods.relinquish_aligned_memory_handler != (RelinquishAlignedMemoryHandler) NULL)
1175
0
    {
1176
0
      memory_methods.relinquish_aligned_memory_handler(memory);
1177
0
      return(NULL);
1178
0
    }
1179
23.5M
#if defined(MAGICKCORE_HAVE_ALIGNED_MALLOC) || defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
1180
23.5M
  free(memory);
1181
#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
1182
  _aligned_free(memory);
1183
#else
1184
  RelinquishMagickMemory(actual_base_address(memory));
1185
#endif
1186
23.5M
  return(NULL);
1187
23.5M
}
1188

1189
/*
1190
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191
%                                                                             %
1192
%                                                                             %
1193
%                                                                             %
1194
%   R e l i n q u i s h M a g i c k M e m o r y                               %
1195
%                                                                             %
1196
%                                                                             %
1197
%                                                                             %
1198
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199
%
1200
%  RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory()
1201
%  or AcquireQuantumMemory() for reuse.
1202
%
1203
%  The format of the RelinquishMagickMemory method is:
1204
%
1205
%      void *RelinquishMagickMemory(void *memory)
1206
%
1207
%  A description of each parameter follows:
1208
%
1209
%    o memory: A pointer to a block of memory to free for reuse.
1210
%
1211
*/
1212
MagickExport void *RelinquishMagickMemory(void *memory)
1213
712M
{
1214
712M
  if (memory == (void *) NULL)
1215
19.8M
    return((void *) NULL);
1216
692M
#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1217
692M
  memory_methods.destroy_memory_handler(memory);
1218
#else
1219
  LockSemaphoreInfo(memory_semaphore);
1220
  assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0);
1221
  assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0);
1222
  if ((*BlockHeader(memory) & PreviousBlockBit) == 0)
1223
    {
1224
      void
1225
        *previous;
1226
1227
      /*
1228
        Coalesce with previous adjacent block.
1229
      */
1230
      previous=PreviousBlock(memory);
1231
      RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous)));
1232
      *BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) |
1233
        (*BlockHeader(previous) & ~SizeMask);
1234
      memory=previous;
1235
    }
1236
  if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0)
1237
    {
1238
      void
1239
        *next;
1240
1241
      /*
1242
        Coalesce with next adjacent block.
1243
      */
1244
      next=NextBlock(memory);
1245
      RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next)));
1246
      *BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) |
1247
        (*BlockHeader(memory) & ~SizeMask);
1248
    }
1249
  *BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory);
1250
  *BlockHeader(NextBlock(memory))&=(~PreviousBlockBit);
1251
  InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory)));
1252
  UnlockSemaphoreInfo(memory_semaphore);
1253
#endif
1254
692M
  return((void *) NULL);
1255
712M
}
1256

1257
/*
1258
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1259
%                                                                             %
1260
%                                                                             %
1261
%                                                                             %
1262
%   R e l i n q u i s h V i r t u a l M e m o r y                             %
1263
%                                                                             %
1264
%                                                                             %
1265
%                                                                             %
1266
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1267
%
1268
%  RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory().
1269
%
1270
%  The format of the RelinquishVirtualMemory method is:
1271
%
1272
%      MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1273
%
1274
%  A description of each parameter follows:
1275
%
1276
%    o memory_info: A pointer to a block of memory to free for reuse.
1277
%
1278
*/
1279
MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
1280
502k
{
1281
502k
  assert(memory_info != (MemoryInfo *) NULL);
1282
502k
  assert(memory_info->signature == MagickCoreSignature);
1283
502k
  if (memory_info->blob != (void *) NULL)
1284
502k
    switch (memory_info->type)
1285
502k
    {
1286
498k
      case AlignedVirtualMemory:
1287
498k
      {
1288
498k
        (void) ShredMagickMemory(memory_info->blob,memory_info->length);
1289
498k
        memory_info->blob=RelinquishAlignedMemory(memory_info->blob);
1290
498k
        break;
1291
0
      }
1292
3.49k
      case MapVirtualMemory:
1293
3.49k
      {
1294
3.49k
        (void) UnmapBlob(memory_info->blob,memory_info->length);
1295
3.49k
        memory_info->blob=NULL;
1296
3.49k
        if (*memory_info->filename != '\0')
1297
3.49k
          (void) RelinquishUniqueFileResource(memory_info->filename);
1298
3.49k
        break;
1299
0
      }
1300
0
      case UnalignedVirtualMemory:
1301
0
      default:
1302
0
      {
1303
0
        (void) ShredMagickMemory(memory_info->blob,memory_info->length);
1304
0
        memory_info->blob=RelinquishMagickMemory(memory_info->blob);
1305
0
        break;
1306
0
      }
1307
502k
    }
1308
502k
  memory_info->signature=(~MagickCoreSignature);
1309
502k
  memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info);
1310
502k
  return(memory_info);
1311
502k
}
1312

1313
/*
1314
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315
%                                                                             %
1316
%                                                                             %
1317
%                                                                             %
1318
%   R e s e t M a g i c k M e m o r y                                         %
1319
%                                                                             %
1320
%                                                                             %
1321
%                                                                             %
1322
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323
%
1324
%  ResetMagickMemory() fills the first size bytes of the memory area pointed to %  by memory with the constant byte c.  We use a volatile pointer when
1325
%  updating the byte string.  Most compilers will avoid optimizing away access
1326
%  to a volatile pointer, even if the pointer appears to be unused after the
1327
%  call.
1328
%
1329
%  The format of the ResetMagickMemory method is:
1330
%
1331
%      void *ResetMagickMemory(void *memory,int c,const size_t size)
1332
%
1333
%  A description of each parameter follows:
1334
%
1335
%    o memory: a pointer to a memory allocation.
1336
%
1337
%    o c: set the memory to this value.
1338
%
1339
%    o size: size of the memory to reset.
1340
%
1341
*/
1342
MagickExport void *ResetMagickMemory(void *memory,int c,const size_t size)
1343
2.16G
{
1344
2.16G
  volatile unsigned char
1345
2.16G
    *p = (volatile unsigned char *) memory;
1346
1347
2.16G
  size_t
1348
2.16G
    n = size;
1349
1350
2.16G
  assert(memory != (void *) NULL);
1351
193G
  while (n-- != 0)
1352
191G
    *p++=(unsigned char) c;
1353
2.16G
  return(memory);
1354
2.16G
}
1355

1356
/*
1357
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358
%                                                                             %
1359
%                                                                             %
1360
%                                                                             %
1361
+   R e s e t V i r t u a l A n o n y m o u s M e m o r y                     %
1362
%                                                                             %
1363
%                                                                             %
1364
%                                                                             %
1365
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366
%
1367
%  ResetVirtualAnonymousMemory() resets the virtual_anonymous_memory value.
1368
%
1369
%  The format of the ResetVirtualAnonymousMemory method is:
1370
%
1371
%      void ResetVirtualAnonymousMemory(void)
1372
%
1373
*/
1374
MagickPrivate void ResetVirtualAnonymousMemory(void)
1375
295
{
1376
295
  virtual_anonymous_memory=0;
1377
295
}
1378

1379
/*
1380
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381
%                                                                             %
1382
%                                                                             %
1383
%                                                                             %
1384
%   R e s i z e M a g i c k M e m o r y                                       %
1385
%                                                                             %
1386
%                                                                             %
1387
%                                                                             %
1388
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1389
%
1390
%  ResizeMagickMemory() changes the size of the memory and returns a pointer to
1391
%  the (possibly moved) block.  The contents will be unchanged up to the
1392
%  lesser of the new and old sizes.
1393
%
1394
%  The format of the ResizeMagickMemory method is:
1395
%
1396
%      void *ResizeMagickMemory(void *memory,const size_t size)
1397
%
1398
%  A description of each parameter follows:
1399
%
1400
%    o memory: A pointer to a memory allocation.
1401
%
1402
%    o size: the new size of the allocated memory.
1403
%
1404
*/
1405
1406
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1407
static inline void *ResizeBlock(void *block,size_t size)
1408
{
1409
  void
1410
    *memory;
1411
1412
  if (block == (void *) NULL)
1413
    return(AcquireBlock(size));
1414
  memory=AcquireBlock(size);
1415
  if (memory == (void *) NULL)
1416
    return((void *) NULL);
1417
  if (size <= (SizeOfBlock(block)-sizeof(size_t)))
1418
    (void) memcpy(memory,block,size);
1419
  else
1420
    (void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
1421
  memory_pool.allocation+=size;
1422
  return(memory);
1423
}
1424
#endif
1425
1426
MagickExport void *ResizeMagickMemory(void *memory,const size_t size)
1427
3.40M
{
1428
3.40M
  void
1429
3.40M
    *block;
1430
1431
3.40M
  if (memory == (void *) NULL)
1432
0
    return(AcquireMagickMemory(size));
1433
3.40M
#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
1434
3.40M
  block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
1435
3.40M
  if (block == (void *) NULL)
1436
0
    memory=RelinquishMagickMemory(memory);
1437
#else
1438
  LockSemaphoreInfo(memory_semaphore);
1439
  block=ResizeBlock(memory,size == 0 ? 1UL : size);
1440
  if (block == (void *) NULL)
1441
    {
1442
      if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
1443
        {
1444
          UnlockSemaphoreInfo(memory_semaphore);
1445
          memory=RelinquishMagickMemory(memory);
1446
          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1447
        }
1448
      block=ResizeBlock(memory,size == 0 ? 1UL : size);
1449
      assert(block != (void *) NULL);
1450
    }
1451
  UnlockSemaphoreInfo(memory_semaphore);
1452
  memory=RelinquishMagickMemory(memory);
1453
#endif
1454
3.40M
  return(block);
1455
3.40M
}
1456

1457
/*
1458
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459
%                                                                             %
1460
%                                                                             %
1461
%                                                                             %
1462
%   R e s i z e Q u a n t u m M e m o r y                                     %
1463
%                                                                             %
1464
%                                                                             %
1465
%                                                                             %
1466
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467
%
1468
%  ResizeQuantumMemory() changes the size of the memory and returns a pointer
1469
%  to the (possibly moved) block.  The contents will be unchanged up to the
1470
%  lesser of the new and old sizes.
1471
%
1472
%  The format of the ResizeQuantumMemory method is:
1473
%
1474
%      void *ResizeQuantumMemory(void *memory,const size_t count,
1475
%        const size_t quantum)
1476
%
1477
%  A description of each parameter follows:
1478
%
1479
%    o memory: A pointer to a memory allocation.
1480
%
1481
%    o count: the number of objects to allocate contiguously.
1482
%
1483
%    o quantum: the size (in bytes) of each object.
1484
%
1485
*/
1486
MagickExport void *ResizeQuantumMemory(void *memory,const size_t count,
1487
  const size_t quantum)
1488
2.50M
{
1489
2.50M
  size_t
1490
2.50M
    size;
1491
1492
2.50M
  if ((HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse) ||
1493
2.50M
      (size > GetMaxMemoryRequest()))
1494
9
    {
1495
9
      errno=ENOMEM;
1496
9
      memory=RelinquishMagickMemory(memory);
1497
9
      return(NULL);
1498
9
    }
1499
2.50M
  return(ResizeMagickMemory(memory,size));
1500
2.50M
}
1501

1502
/*
1503
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1504
%                                                                             %
1505
%                                                                             %
1506
%                                                                             %
1507
%   S e t M a g i c k A l i g n e d M e m o r y M e t h o d s                 %
1508
%                                                                             %
1509
%                                                                             %
1510
%                                                                             %
1511
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512
%
1513
%  SetMagickAlignedMemoryMethods() sets the methods to acquire and relinquish
1514
%  aligned memory.
1515
%
1516
%  The format of the SetMagickAlignedMemoryMethods() method is:
1517
%
1518
%      void SetMagickAlignedMemoryMethods(
1519
%        AcquireAlignedMemoryHandler acquire_aligned_memory_handler,
1520
%        RelinquishAlignedMemoryHandler relinquish_aligned_memory_handler)
1521
%
1522
%  A description of each parameter follows:
1523
%
1524
%    o acquire_memory_handler: method to acquire aligned memory.
1525
%
1526
%    o relinquish_aligned_memory_handler: method to relinquish aligned memory.
1527
%
1528
*/
1529
MagickExport void SetMagickAlignedMemoryMethods(
1530
  AcquireAlignedMemoryHandler acquire_aligned_memory_handler,
1531
  RelinquishAlignedMemoryHandler relinquish_aligned_memory_handler)
1532
0
{
1533
0
  memory_methods.acquire_aligned_memory_handler=acquire_aligned_memory_handler;
1534
0
  memory_methods.relinquish_aligned_memory_handler=
1535
0
      relinquish_aligned_memory_handler;
1536
0
}
1537

1538
/*
1539
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540
%                                                                             %
1541
%                                                                             %
1542
%                                                                             %
1543
%   S e t M a g i c k M e m o r y M e t h o d s                               %
1544
%                                                                             %
1545
%                                                                             %
1546
%                                                                             %
1547
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548
%
1549
%  SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy
1550
%  memory. Your custom memory methods must be set prior to the
1551
%  MagickCoreGenesis() method.
1552
%
1553
%  The format of the SetMagickMemoryMethods() method is:
1554
%
1555
%      void SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler,
1556
%        ResizeMemoryHandler resize_memory_handler,
1557
%        DestroyMemoryHandler destroy_memory_handler)
1558
%
1559
%  A description of each parameter follows:
1560
%
1561
%    o acquire_memory_handler: method to acquire memory (e.g. malloc).
1562
%
1563
%    o resize_memory_handler: method to resize memory (e.g. realloc).
1564
%
1565
%    o destroy_memory_handler: method to destroy memory (e.g. free).
1566
%
1567
*/
1568
MagickExport void SetMagickMemoryMethods(
1569
  AcquireMemoryHandler acquire_memory_handler,
1570
  ResizeMemoryHandler resize_memory_handler,
1571
  DestroyMemoryHandler destroy_memory_handler)
1572
0
{
1573
  /*
1574
    Set memory methods.
1575
  */
1576
0
  if (acquire_memory_handler != (AcquireMemoryHandler) NULL)
1577
0
    memory_methods.acquire_memory_handler=acquire_memory_handler;
1578
0
  if (resize_memory_handler != (ResizeMemoryHandler) NULL)
1579
0
    memory_methods.resize_memory_handler=resize_memory_handler;
1580
0
  if (destroy_memory_handler != (DestroyMemoryHandler) NULL)
1581
0
    memory_methods.destroy_memory_handler=destroy_memory_handler;
1582
0
}
1583

1584
/*
1585
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586
%                                                                             %
1587
%                                                                             %
1588
%                                                                             %
1589
+   S e t M a x M e m o r y R e q u e s t                                     %
1590
%                                                                             %
1591
%                                                                             %
1592
%                                                                             %
1593
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594
%
1595
%  SetMaxMemoryRequest() sets the max memory request value.
1596
%
1597
%  The format of the SetMaxMemoryRequest method is:
1598
%
1599
%      void SetMaxMemoryRequest(const MagickSizeType limit)
1600
%
1601
%  A description of each parameter follows:
1602
%
1603
%    o limit: the maximum memory request limit.
1604
%
1605
*/
1606
MagickPrivate void SetMaxMemoryRequest(const MagickSizeType limit)
1607
295
{
1608
295
  max_memory_request=(size_t) MagickMin(limit,GetMaxMemoryRequestFromPolicy());
1609
295
}
1610

1611
/*
1612
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613
%                                                                             %
1614
%                                                                             %
1615
%                                                                             %
1616
+   S e t M a x P r o f i l e S i z e                                         %
1617
%                                                                             %
1618
%                                                                             %
1619
%                                                                             %
1620
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621
%
1622
%  SetMaxProfileSize() sets the max profile size value.
1623
%
1624
%  The format of the SetMaxProfileSize method is:
1625
%
1626
%      void SetMaxProfileSize(const MagickSizeType limit)
1627
%
1628
%  A description of each parameter follows:
1629
%
1630
%    o limit: the maximum profile size limit.
1631
%
1632
*/
1633
MagickPrivate void SetMaxProfileSize(const MagickSizeType limit)
1634
295
{
1635
295
  max_profile_size=(size_t) MagickMin(limit,GetMaxProfileSizeFromPolicy());
1636
295
}
1637

1638
/*
1639
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640
%                                                                             %
1641
%                                                                             %
1642
%                                                                             %
1643
%   S h r e d M a g i c k M e m o r y                                         %
1644
%                                                                             %
1645
%                                                                             %
1646
%                                                                             %
1647
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1648
%
1649
%  ShredMagickMemory() overwrites the specified memory buffer with random data.
1650
%  The overwrite is optional and is only required to help keep the contents of
1651
%  the memory buffer private.
1652
%
1653
%  The format of the ShredMagickMemory method is:
1654
%
1655
%      MagickBooleanType ShredMagickMemory(void *memory,const size_t length)
1656
%
1657
%  A description of each parameter follows.
1658
%
1659
%    o memory:  Specifies the memory buffer.
1660
%
1661
%    o length:  Specifies the length of the memory buffer.
1662
%
1663
*/
1664
MagickPrivate MagickBooleanType ShredMagickMemory(void *memory,
1665
  const size_t length)
1666
2.83M
{
1667
2.83M
  RandomInfo
1668
2.83M
    *random_info;
1669
1670
2.83M
  size_t
1671
2.83M
    quantum;
1672
1673
2.83M
  ssize_t
1674
2.83M
    i;
1675
1676
2.83M
  static ssize_t
1677
2.83M
    passes = -1;
1678
1679
2.83M
  StringInfo
1680
2.83M
    *key;
1681
1682
2.83M
  if ((memory == NULL) || (length == 0))
1683
0
    return(MagickFalse);
1684
2.83M
  if (passes == -1)
1685
104
    {
1686
104
      char
1687
104
        *property;
1688
1689
104
      passes=0;
1690
104
      property=GetEnvironmentValue("MAGICK_SHRED_PASSES");
1691
104
      if (property != (char *) NULL)
1692
0
        {
1693
0
          passes=(ssize_t) StringToInteger(property);
1694
0
          property=DestroyString(property);
1695
0
        }
1696
104
      property=GetPolicyValue("system:shred");
1697
104
      if (property != (char *) NULL)
1698
0
        {
1699
0
          passes=(ssize_t) StringToInteger(property);
1700
0
          property=DestroyString(property);
1701
0
        }
1702
104
    }
1703
2.83M
  if (passes == 0)
1704
2.83M
    return(MagickTrue);
1705
  /*
1706
    Overwrite the memory buffer with random data.
1707
  */
1708
0
  quantum=(size_t) MagickMin(length,MagickMinBufferExtent);
1709
0
  random_info=AcquireRandomInfo();
1710
0
  key=GetRandomKey(random_info,quantum);
1711
0
  for (i=0; i < passes; i++)
1712
0
  {
1713
0
    size_t
1714
0
      j;
1715
1716
0
    unsigned char
1717
0
      *p = (unsigned char *) memory;
1718
1719
0
    for (j=0; j < length; j+=quantum)
1720
0
    {
1721
0
      if (i != 0)
1722
0
        SetRandomKey(random_info,quantum,GetStringInfoDatum(key));
1723
0
      (void) memcpy(p,GetStringInfoDatum(key),(size_t)
1724
0
        MagickMin(quantum,length-j));
1725
0
      p+=(ptrdiff_t) quantum;
1726
0
    }
1727
0
    if (j < length)
1728
0
      break;
1729
0
  }
1730
0
  key=DestroyStringInfo(key);
1731
0
  random_info=DestroyRandomInfo(random_info);
1732
0
  return(i < passes ? MagickFalse : MagickTrue);
1733
2.83M
}