Coverage Report

Created: 2026-03-31 06:56

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