Coverage Report

Created: 2025-08-12 07:37

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