You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1554 lines
54 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% M M EEEEE M M OOO RRRR Y Y %
% MM MM E MM MM O O R R Y Y %
% M M M EEE M M M O O RRRR Y %
% M M E M M O O R R Y %
% M M EEEEE M M OOO R R Y %
% %
% %
% MagickCore Memory Allocation Methods %
% %
% Software Design %
% Cristy %
% July 1998 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% We provide these memory allocators:
%
% AcquireCriticalMemory(): allocate a small memory request with
% AcquireMagickMemory(), however, on fail throw a fatal exception and exit.
% Free the memory reserve with RelinquishMagickMemory().
% AcquireAlignedMemory(): allocate a small memory request that is aligned
% on a cache line. On fail, return NULL for possible recovery.
% Free the memory reserve with RelinquishMagickMemory().
% AcquireMagickMemory()/ResizeMagickMemory(): allocate a small to medium
% memory request, typically with malloc()/realloc(). On fail, return NULL
% for possible recovery. Free the memory reserve with
% RelinquishMagickMemory().
% AcquireQuantumMemory()/ResizeQuantumMemory(): allocate a small to medium
% memory request. This is a secure memory allocator as it accepts two
% parameters, count and quantum, to ensure the request does not overflow.
% It also check to ensure the request does not exceed the maximum memory
% per the security policy. Free the memory reserve with
% RelinquishMagickMemory().
% AcquireVirtualMemory(): allocate a large memory request either in heap,
% memory-mapped, or memory-mapped on disk depending on whether heap
% allocation fails or if the request exceeds the maximum memory policy.
% Free the memory reserve with RelinquishVirtualMemory().
% ResetMagickMemory(): fills the bytes of the memory area with a constant
% byte.
%
% In addition, we provide hooks for your own memory constructor/destructors.
% You can also utilize our internal custom allocator as follows: Segregate
% our memory requirements from any program that calls our API. This should
% help reduce the risk of others changing our program state or causing memory
% corruption.
%
% Our custom memory allocation manager implements a best-fit allocation policy
% using segregated free lists. It uses a linear distribution of size classes
% for lower sizes and a power of two distribution of size classes at higher
% sizes. It is based on the paper, "Fast Memory Allocation using Lazy Fits."
% written by Yoo C. Chung.
%
% By default, C's standard library is used (e.g. malloc); use the
% custom memory allocator by defining MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT
% to allocate memory with private anonymous mapping rather than from the
% heap.
%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/image-private.h"
#include "MagickCore/memory_.h"
#include "MagickCore/memory-private.h"
#include "MagickCore/policy.h"
#include "MagickCore/resource_.h"
#include "MagickCore/semaphore.h"
#include "MagickCore/string_.h"
#include "MagickCore/string-private.h"
#include "MagickCore/utility-private.h"
/*
Define declarations.
*/
#define BlockFooter(block,size) \
((size_t *) ((char *) (block)+(size)-2*sizeof(size_t)))
#define BlockHeader(block) ((size_t *) (block)-1)
#define BlockThreshold 1024
#define MaxBlockExponent 16
#define MaxBlocks ((BlockThreshold/(4*sizeof(size_t)))+MaxBlockExponent+1)
#define MaxSegments 1024
#define NextBlock(block) ((char *) (block)+SizeOfBlock(block))
#define NextBlockInList(block) (*(void **) (block))
#define PreviousBlock(block) ((char *) (block)-(*((size_t *) (block)-2)))
#define PreviousBlockBit 0x01
#define PreviousBlockInList(block) (*((void **) (block)+1))
#define SegmentSize (2*1024*1024)
#define SizeMask (~0x01)
#define SizeOfBlock(block) (*BlockHeader(block) & SizeMask)
/*
Typedef declarations.
*/
typedef enum
{
UndefinedVirtualMemory,
AlignedVirtualMemory,
MapVirtualMemory,
UnalignedVirtualMemory
} VirtualMemoryType;
typedef struct _DataSegmentInfo
{
void
*allocation,
*bound;
MagickBooleanType
mapped;
size_t
length;
struct _DataSegmentInfo
*previous,
*next;
} DataSegmentInfo;
typedef struct _MagickMemoryMethods
{
AcquireMemoryHandler
acquire_memory_handler;
ResizeMemoryHandler
resize_memory_handler;
DestroyMemoryHandler
destroy_memory_handler;
AcquireAlignedMemoryHandler
acquire_aligned_memory_handler;
RelinquishAlignedMemoryHandler
relinquish_aligned_memory_handler;
} MagickMemoryMethods;
struct _MemoryInfo
{
char
filename[MagickPathExtent];
VirtualMemoryType
type;
size_t
length;
void
*blob;
size_t
signature;
};
typedef struct _MemoryPool
{
size_t
allocation;
void
*blocks[MaxBlocks+1];
size_t
number_segments;
DataSegmentInfo
*segments[MaxSegments],
segment_pool[MaxSegments];
} MemoryPool;
/*
Global declarations.
*/
static size_t
max_memory_request = 0,
virtual_anonymous_memory = 0;
#if defined _MSC_VER
static void *MSCMalloc(size_t size)
{
return(malloc(size));
}
static void *MSCRealloc(void* ptr, size_t size)
{
return(realloc(ptr,size));
}
static void MSCFree(void* ptr)
{
free(ptr);
}
#endif
static MagickMemoryMethods
memory_methods =
{
#if defined _MSC_VER
(AcquireMemoryHandler) MSCMalloc,
(ResizeMemoryHandler) MSCRealloc,
(DestroyMemoryHandler) MSCFree,
#else
(AcquireMemoryHandler) malloc,
(ResizeMemoryHandler) realloc,
(DestroyMemoryHandler) free,
#endif
(AcquireAlignedMemoryHandler) NULL,
(RelinquishAlignedMemoryHandler) NULL
};
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
static MemoryPool
memory_pool;
static SemaphoreInfo
*memory_semaphore = (SemaphoreInfo *) NULL;
static volatile DataSegmentInfo
*free_segments = (DataSegmentInfo *) NULL;
/*
Forward declarations.
*/
static MagickBooleanType
ExpandHeap(size_t);
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A c q u i r e A l i g n e d M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireAlignedMemory() returns a pointer to a block of memory whose size is
% at least (count*quantum) bytes, and whose address is aligned on a cache line.
%
% The format of the AcquireAlignedMemory method is:
%
% void *AcquireAlignedMemory(const size_t count,const size_t quantum)
%
% A description of each parameter follows:
%
% o count: the number of objects to allocate contiguously.
%
% o quantum: the size (in bytes) of each object.
%
*/
#if defined(MAGICKCORE_HAVE_ALIGNED_MALLOC)
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_STDC
static inline void *AcquireAlignedMemory_STDC(const size_t size)
{
size_t
extent = CACHE_ALIGNED(size);
if (extent < size)
{
errno=ENOMEM;
return(NULL);
}
return(aligned_alloc(CACHE_LINE_SIZE,extent));
}
#elif defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_POSIX
static inline void *AcquireAlignedMemory_POSIX(const size_t size)
{
void
*memory;
if (posix_memalign(&memory,CACHE_LINE_SIZE,size))
return(NULL);
return(memory);
}
#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_WinAPI
static inline void *AcquireAlignedMemory_WinAPI(const size_t size)
{
return(_aligned_malloc(size,CACHE_LINE_SIZE));
}
#else
#define ALIGNMENT_OVERHEAD \
(MAGICKCORE_MAX_ALIGNMENT_PADDING(CACHE_LINE_SIZE) + MAGICKCORE_SIZEOF_VOID_P)
static inline void *reserve_space_for_actual_base_address(void *const p)
{
return((void **) p+1);
}
static inline void **pointer_to_space_for_actual_base_address(void *const p)
{
return((void **) p-1);
}
static inline void *actual_base_address(void *const p)
{
return(*pointer_to_space_for_actual_base_address(p));
}
static inline void *align_to_cache(void *const p)
{
return((void *) CACHE_ALIGNED((MagickAddressType) p));
}
static inline void *adjust(void *const p)
{
return(align_to_cache(reserve_space_for_actual_base_address(p)));
}
#define AcquireAlignedMemory_Actual AcquireAlignedMemory_Generic
static inline void *AcquireAlignedMemory_Generic(const size_t size)
{
size_t
extent;
void
*memory,
*p;
#if SIZE_MAX < ALIGNMENT_OVERHEAD
#error "CACHE_LINE_SIZE is way too big."
#endif
extent=(size+ALIGNMENT_OVERHEAD);
if (extent <= size)
{
errno=ENOMEM;
return(NULL);
}
p=AcquireMagickMemory(extent);
if (p == NULL)
return(NULL);
memory=adjust(p);
*pointer_to_space_for_actual_base_address(memory)=p;
return(memory);
}
#endif
MagickExport void *AcquireAlignedMemory(const size_t count,const size_t quantum)
{
size_t
size;
if (HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse)
{
errno=ENOMEM;
return(NULL);
}
if (memory_methods.acquire_aligned_memory_handler != (AcquireAlignedMemoryHandler) NULL)
return(memory_methods.acquire_aligned_memory_handler(size,CACHE_LINE_SIZE));
return(AcquireAlignedMemory_Actual(size));
}
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ A c q u i r e B l o c k %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireBlock() returns a pointer to a block of memory at least size bytes
% suitably aligned for any use.
%
% The format of the AcquireBlock method is:
%
% void *AcquireBlock(const size_t size)
%
% A description of each parameter follows:
%
% o size: the size of the memory in bytes to allocate.
%
*/
static inline size_t AllocationPolicy(size_t size)
{
size_t
blocksize;
/*
The linear distribution.
*/
assert(size != 0);
assert(size % (4*sizeof(size_t)) == 0);
if (size <= BlockThreshold)
return(size/(4*sizeof(size_t)));
/*
Check for the largest block size.
*/
if (size > (size_t) (BlockThreshold*(1L << (MaxBlockExponent-1L))))
return(MaxBlocks-1L);
/*
Otherwise use a power of two distribution.
*/
blocksize=BlockThreshold/(4*sizeof(size_t));
for ( ; size > BlockThreshold; size/=2)
blocksize++;
assert(blocksize > (BlockThreshold/(4*sizeof(size_t))));
assert(blocksize < (MaxBlocks-1L));
return(blocksize);
}
static inline void InsertFreeBlock(void *block,const size_t i)
{
void
*next,
*previous;
size_t
size;
size=SizeOfBlock(block);
previous=(void *) NULL;
next=memory_pool.blocks[i];
while ((next != (void *) NULL) && (SizeOfBlock(next) < size))
{
previous=next;
next=NextBlockInList(next);
}
PreviousBlockInList(block)=previous;
NextBlockInList(block)=next;
if (previous != (void *) NULL)
NextBlockInList(previous)=block;
else
memory_pool.blocks[i]=block;
if (next != (void *) NULL)
PreviousBlockInList(next)=block;
}
static inline void RemoveFreeBlock(void *block,const size_t i)
{
void
*next,
*previous;
next=NextBlockInList(block);
previous=PreviousBlockInList(block);
if (previous == (void *) NULL)
memory_pool.blocks[i]=next;
else
NextBlockInList(previous)=next;
if (next != (void *) NULL)
PreviousBlockInList(next)=previous;
}
static void *AcquireBlock(size_t size)
{
size_t
i;
void
*block;
/*
Find free block.
*/
size=(size_t) (size+sizeof(size_t)+6*sizeof(size_t)-1) & -(4U*sizeof(size_t));
i=AllocationPolicy(size);
block=memory_pool.blocks[i];
while ((block != (void *) NULL) && (SizeOfBlock(block) < size))
block=NextBlockInList(block);
if (block == (void *) NULL)
{
i++;
while (memory_pool.blocks[i] == (void *) NULL)
i++;
block=memory_pool.blocks[i];
if (i >= MaxBlocks)
return((void *) NULL);
}
assert((*BlockHeader(NextBlock(block)) & PreviousBlockBit) == 0);
assert(SizeOfBlock(block) >= size);
RemoveFreeBlock(block,AllocationPolicy(SizeOfBlock(block)));
if (SizeOfBlock(block) > size)
{
size_t
blocksize;
void
*next;
/*
Split block.
*/
next=(char *) block+size;
blocksize=SizeOfBlock(block)-size;
*BlockHeader(next)=blocksize;
*BlockFooter(next,blocksize)=blocksize;
InsertFreeBlock(next,AllocationPolicy(blocksize));
*BlockHeader(block)=size | (*BlockHeader(block) & ~SizeMask);
}
assert(size == SizeOfBlock(block));
*BlockHeader(NextBlock(block))|=PreviousBlockBit;
memory_pool.allocation+=size;
return(block);
}
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A c q u i r e M a g i c k M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireMagickMemory() returns a pointer to a block of memory at least size
% bytes suitably aligned for any use.
%
% The format of the AcquireMagickMemory method is:
%
% void *AcquireMagickMemory(const size_t size)
%
% A description of each parameter follows:
%
% o size: the size of the memory in bytes to allocate.
%
*/
MagickExport void *AcquireMagickMemory(const size_t size)
{
void
*memory;
#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
memory=memory_methods.acquire_memory_handler(size == 0 ? 1UL : size);
#else
if (memory_semaphore == (SemaphoreInfo *) NULL)
ActivateSemaphoreInfo(&memory_semaphore);
if (free_segments == (DataSegmentInfo *) NULL)
{
LockSemaphoreInfo(memory_semaphore);
if (free_segments == (DataSegmentInfo *) NULL)
{
ssize_t
i;
assert(2*sizeof(size_t) > (size_t) (~SizeMask));
(void) memset(&memory_pool,0,sizeof(memory_pool));
memory_pool.allocation=SegmentSize;
memory_pool.blocks[MaxBlocks]=(void *) (-1);
for (i=0; i < MaxSegments; i++)
{
if (i != 0)
memory_pool.segment_pool[i].previous=
(&memory_pool.segment_pool[i-1]);
if (i != (MaxSegments-1))
memory_pool.segment_pool[i].next=(&memory_pool.segment_pool[i+1]);
}
free_segments=(&memory_pool.segment_pool[0]);
}
UnlockSemaphoreInfo(memory_semaphore);
}
LockSemaphoreInfo(memory_semaphore);
memory=AcquireBlock(size == 0 ? 1UL : size);
if (memory == (void *) NULL)
{
if (ExpandHeap(size == 0 ? 1UL : size) != MagickFalse)
memory=AcquireBlock(size == 0 ? 1UL : size);
}
UnlockSemaphoreInfo(memory_semaphore);
#endif
return(memory);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A c q u i r e C r i t i c a l M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireCriticalMemory() is just like AcquireMagickMemory(), throws a fatal
% exception if the memory cannot be acquired.
%
% That is, AcquireCriticalMemory() returns a pointer to a block of memory that
% is at least size bytes, and that is suitably aligned for any use; however,
% if this is not possible, it throws an exception and terminates the program
% as unceremoniously as possible.
%
% The format of the AcquireCriticalMemory method is:
%
% void *AcquireCriticalMemory(const size_t size)
%
% A description of each parameter follows:
%
% o size: the size (in bytes) of the memory to allocate.
%
*/
MagickExport void *AcquireCriticalMemory(const size_t size)
{
void
*memory;
/*
Fail if memory request cannot be fulfilled.
*/
memory=AcquireMagickMemory(size);
if (memory == (void *) NULL)
ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
return(memory);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A c q u i r e Q u a n t u m M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireQuantumMemory() returns a pointer to a block of memory at least
% count * quantum bytes suitably aligned for any use.
%
% The format of the AcquireQuantumMemory method is:
%
% void *AcquireQuantumMemory(const size_t count,const size_t quantum)
%
% A description of each parameter follows:
%
% o count: the number of objects to allocate contiguously.
%
% o quantum: the size (in bytes) of each object.
%
*/
MagickExport void *AcquireQuantumMemory(const size_t count,const size_t quantum)
{
size_t
size;
if ((HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse) ||
(size > GetMaxMemoryRequest()))
{
errno=ENOMEM;
return(NULL);
}
return(AcquireMagickMemory(size));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A c q u i r e V i r t u a l M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireVirtualMemory() allocates a pointer to a block of memory at least
% size bytes suitably aligned for any use. In addition to heap, it also
% supports memory-mapped and file-based memory-mapped memory requests.
%
% The format of the AcquireVirtualMemory method is:
%
% MemoryInfo *AcquireVirtualMemory(const size_t count,const size_t quantum)
%
% A description of each parameter follows:
%
% o count: the number of objects to allocate contiguously.
%
% o quantum: the size (in bytes) of each object.
%
*/
MagickExport MemoryInfo *AcquireVirtualMemory(const size_t count,
const size_t quantum)
{
char
*value;
MemoryInfo
*memory_info;
size_t
size;
if (HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse)
{
errno=ENOMEM;
return((MemoryInfo *) NULL);
}
if (virtual_anonymous_memory == 0)
{
virtual_anonymous_memory=1;
value=GetPolicyValue("system:memory-map");
if (LocaleCompare(value,"anonymous") == 0)
{
/*
The security policy sets anonymous mapping for the memory request.
*/
#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
virtual_anonymous_memory=2;
#endif
}
value=DestroyString(value);
}
memory_info=(MemoryInfo *) MagickAssumeAligned(AcquireAlignedMemory(1,
sizeof(*memory_info)));
if (memory_info == (MemoryInfo *) NULL)
ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
(void) memset(memory_info,0,sizeof(*memory_info));
memory_info->length=size;
memory_info->signature=MagickCoreSignature;
if ((virtual_anonymous_memory == 1) && (size <= GetMaxMemoryRequest()))
{
memory_info->blob=AcquireAlignedMemory(1,size);
if (memory_info->blob != NULL)
memory_info->type=AlignedVirtualMemory;
}
if (memory_info->blob == NULL)
{
/*
Acquire anonymous memory map.
*/
memory_info->blob=NULL;
if (size <= GetMaxMemoryRequest())
memory_info->blob=MapBlob(-1,IOMode,0,size);
if (memory_info->blob != NULL)
memory_info->type=MapVirtualMemory;
else
{
int
file;
/*
Anonymous memory mapping failed, try file-backed memory mapping.
*/
file=AcquireUniqueFileResource(memory_info->filename);
if (file != -1)
{
MagickOffsetType
offset;
offset=(MagickOffsetType) lseek(file,size-1,SEEK_SET);
if ((offset == (MagickOffsetType) (size-1)) &&
(write(file,"",1) == 1))
{
#if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
memory_info->blob=MapBlob(file,IOMode,0,size);
#else
if (posix_fallocate(file,0,(MagickOffsetType) size) == 0)
memory_info->blob=MapBlob(file,IOMode,0,size);
#endif
if (memory_info->blob != NULL)
memory_info->type=MapVirtualMemory;
else
{
(void) RelinquishUniqueFileResource(
memory_info->filename);
*memory_info->filename='\0';
}
}
(void) close(file);
}
}
}
if (memory_info->blob == NULL)
{
memory_info->blob=AcquireQuantumMemory(1,size);
if (memory_info->blob != NULL)
memory_info->type=UnalignedVirtualMemory;
}
if (memory_info->blob == NULL)
memory_info=RelinquishVirtualMemory(memory_info);
return(memory_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C o p y M a g i c k M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CopyMagickMemory() copies size bytes from memory area source to the
% destination. Copying between objects that overlap will take place
% correctly. It returns destination.
%
% The format of the CopyMagickMemory method is:
%
% void *CopyMagickMemory(void *magick_restrict destination,
% const void *magick_restrict source,const size_t size)
%
% A description of each parameter follows:
%
% o destination: the destination.
%
% o source: the source.
%
% o size: the size of the memory in bytes to allocate.
%
*/
MagickExport void *CopyMagickMemory(void *magick_restrict destination,
const void *magick_restrict source,const size_t size)
{
const unsigned char
*p;
unsigned char
*q;
assert(destination != (void *) NULL);
assert(source != (const void *) NULL);
p=(const unsigned char *) source;
q=(unsigned char *) destination;
if (((q+size) < p) || (q > (p+size)))
switch (size)
{
default: return(memcpy(destination,source,size));
case 8: *q++=(*p++);
case 7: *q++=(*p++);
case 6: *q++=(*p++);
case 5: *q++=(*p++);
case 4: *q++=(*p++);
case 3: *q++=(*p++);
case 2: *q++=(*p++);
case 1: *q++=(*p++);
case 0: return(destination);
}
return(memmove(destination,source,size));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ D e s t r o y M a g i c k M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DestroyMagickMemory() deallocates memory associated with the memory manager.
%
% The format of the DestroyMagickMemory method is:
%
% DestroyMagickMemory(void)
%
*/
MagickExport void DestroyMagickMemory(void)
{
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
ssize_t
i;
if (memory_semaphore == (SemaphoreInfo *) NULL)
ActivateSemaphoreInfo(&memory_semaphore);
LockSemaphoreInfo(memory_semaphore);
for (i=0; i < (ssize_t) memory_pool.number_segments; i++)
if (memory_pool.segments[i]->mapped == MagickFalse)
memory_methods.destroy_memory_handler(
memory_pool.segments[i]->allocation);
else
(void) UnmapBlob(memory_pool.segments[i]->allocation,
memory_pool.segments[i]->length);
free_segments=(DataSegmentInfo *) NULL;
(void) memset(&memory_pool,0,sizeof(memory_pool));
UnlockSemaphoreInfo(memory_semaphore);
RelinquishSemaphoreInfo(&memory_semaphore);
#endif
}
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ E x p a n d H e a p %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ExpandHeap() get more memory from the system. It returns MagickTrue on
% success otherwise MagickFalse.
%
% The format of the ExpandHeap method is:
%
% MagickBooleanType ExpandHeap(size_t size)
%
% A description of each parameter follows:
%
% o size: the size of the memory in bytes we require.
%
*/
static MagickBooleanType ExpandHeap(size_t size)
{
DataSegmentInfo
*segment_info;
MagickBooleanType
mapped;
ssize_t
i;
void
*block;
size_t
blocksize;
void
*segment;
blocksize=((size+12*sizeof(size_t))+SegmentSize-1) & -SegmentSize;
assert(memory_pool.number_segments < MaxSegments);
segment=MapBlob(-1,IOMode,0,blocksize);
mapped=segment != (void *) NULL ? MagickTrue : MagickFalse;
if (segment == (void *) NULL)
segment=(void *) memory_methods.acquire_memory_handler(blocksize);
if (segment == (void *) NULL)
return(MagickFalse);
segment_info=(DataSegmentInfo *) free_segments;
free_segments=segment_info->next;
segment_info->mapped=mapped;
segment_info->length=blocksize;
segment_info->allocation=segment;
segment_info->bound=(char *) segment+blocksize;
i=(ssize_t) memory_pool.number_segments-1;
for ( ; (i >= 0) && (memory_pool.segments[i]->allocation > segment); i--)
memory_pool.segments[i+1]=memory_pool.segments[i];
memory_pool.segments[i+1]=segment_info;
memory_pool.number_segments++;
size=blocksize-12*sizeof(size_t);
block=(char *) segment_info->allocation+4*sizeof(size_t);
*BlockHeader(block)=size | PreviousBlockBit;
*BlockFooter(block,size)=size;
InsertFreeBlock(block,AllocationPolicy(size));
block=NextBlock(block);
assert(block < segment_info->bound);
*BlockHeader(block)=2*sizeof(size_t);
*BlockHeader(NextBlock(block))=PreviousBlockBit;
return(MagickTrue);
}
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t M a g i c k M e m o r y M e t h o d s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMagickMemoryMethods() gets the methods to acquire, resize, and destroy
% memory.
%
% The format of the GetMagickMemoryMethods() method is:
%
% void GetMagickMemoryMethods(AcquireMemoryHandler *acquire_memory_handler,
% ResizeMemoryHandler *resize_memory_handler,
% DestroyMemoryHandler *destroy_memory_handler)
%
% A description of each parameter follows:
%
% o acquire_memory_handler: method to acquire memory (e.g. malloc).
%
% o resize_memory_handler: method to resize memory (e.g. realloc).
%
% o destroy_memory_handler: method to destroy memory (e.g. free).
%
*/
MagickExport void GetMagickMemoryMethods(
AcquireMemoryHandler *acquire_memory_handler,
ResizeMemoryHandler *resize_memory_handler,
DestroyMemoryHandler *destroy_memory_handler)
{
assert(acquire_memory_handler != (AcquireMemoryHandler *) NULL);
assert(resize_memory_handler != (ResizeMemoryHandler *) NULL);
assert(destroy_memory_handler != (DestroyMemoryHandler *) NULL);
*acquire_memory_handler=memory_methods.acquire_memory_handler;
*resize_memory_handler=memory_methods.resize_memory_handler;
*destroy_memory_handler=memory_methods.destroy_memory_handler;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t M a x M e m o r y R e q u e s t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMaxMemoryRequest() returns the max_memory_request value.
%
% The format of the GetMaxMemoryRequest method is:
%
% size_t GetMaxMemoryRequest(void)
%
*/
MagickExport size_t GetMaxMemoryRequest(void)
{
#define MinMemoryRequest "16MiB"
if (max_memory_request == 0)
{
char
*value;
max_memory_request=(size_t) MagickULLConstant(~0);
value=GetPolicyValue("system:max-memory-request");
if (value != (char *) NULL)
{
/*
The security policy sets a max memory request limit.
*/
max_memory_request=MagickMax(StringToSizeType(value,100.0),
StringToSizeType(MinMemoryRequest,100.0));
value=DestroyString(value);
}
}
return(MagickMin(max_memory_request,MAGICK_SSIZE_MAX));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t V i r t u a l M e m o r y B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetVirtualMemoryBlob() returns the virtual memory blob associated with the
% specified MemoryInfo structure.
%
% The format of the GetVirtualMemoryBlob method is:
%
% void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
%
% A description of each parameter follows:
%
% o memory_info: The MemoryInfo structure.
*/
MagickExport void *GetVirtualMemoryBlob(const MemoryInfo *memory_info)
{
assert(memory_info != (const MemoryInfo *) NULL);
assert(memory_info->signature == MagickCoreSignature);
return(memory_info->blob);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e l i n q u i s h A l i g n e d M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RelinquishAlignedMemory() frees memory acquired with AcquireAlignedMemory()
% or reuse.
%
% The format of the RelinquishAlignedMemory method is:
%
% void *RelinquishAlignedMemory(void *memory)
%
% A description of each parameter follows:
%
% o memory: A pointer to a block of memory to free for reuse.
%
*/
MagickExport void *RelinquishAlignedMemory(void *memory)
{
if (memory == (void *) NULL)
return((void *) NULL);
if (memory_methods.relinquish_aligned_memory_handler != (RelinquishAlignedMemoryHandler) NULL)
{
memory_methods.relinquish_aligned_memory_handler(memory);
return(NULL);
}
#if defined(MAGICKCORE_HAVE_ALIGNED_MALLOC) || defined(MAGICKCORE_HAVE_POSIX_MEMALIGN)
free(memory);
#elif defined(MAGICKCORE_HAVE__ALIGNED_MALLOC)
_aligned_free(memory);
#else
RelinquishMagickMemory(actual_base_address(memory));
#endif
return(NULL);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e l i n q u i s h M a g i c k M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RelinquishMagickMemory() frees memory acquired with AcquireMagickMemory()
% or AcquireQuantumMemory() for reuse.
%
% The format of the RelinquishMagickMemory method is:
%
% void *RelinquishMagickMemory(void *memory)
%
% A description of each parameter follows:
%
% o memory: A pointer to a block of memory to free for reuse.
%
*/
MagickExport void *RelinquishMagickMemory(void *memory)
{
if (memory == (void *) NULL)
return((void *) NULL);
#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
memory_methods.destroy_memory_handler(memory);
#else
LockSemaphoreInfo(memory_semaphore);
assert((SizeOfBlock(memory) % (4*sizeof(size_t))) == 0);
assert((*BlockHeader(NextBlock(memory)) & PreviousBlockBit) != 0);
if ((*BlockHeader(memory) & PreviousBlockBit) == 0)
{
void
*previous;
/*
Coalesce with previous adjacent block.
*/
previous=PreviousBlock(memory);
RemoveFreeBlock(previous,AllocationPolicy(SizeOfBlock(previous)));
*BlockHeader(previous)=(SizeOfBlock(previous)+SizeOfBlock(memory)) |
(*BlockHeader(previous) & ~SizeMask);
memory=previous;
}
if ((*BlockHeader(NextBlock(NextBlock(memory))) & PreviousBlockBit) == 0)
{
void
*next;
/*
Coalesce with next adjacent block.
*/
next=NextBlock(memory);
RemoveFreeBlock(next,AllocationPolicy(SizeOfBlock(next)));
*BlockHeader(memory)=(SizeOfBlock(memory)+SizeOfBlock(next)) |
(*BlockHeader(memory) & ~SizeMask);
}
*BlockFooter(memory,SizeOfBlock(memory))=SizeOfBlock(memory);
*BlockHeader(NextBlock(memory))&=(~PreviousBlockBit);
InsertFreeBlock(memory,AllocationPolicy(SizeOfBlock(memory)));
UnlockSemaphoreInfo(memory_semaphore);
#endif
return((void *) NULL);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e l i n q u i s h V i r t u a l M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RelinquishVirtualMemory() frees memory acquired with AcquireVirtualMemory().
%
% The format of the RelinquishVirtualMemory method is:
%
% MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
%
% A description of each parameter follows:
%
% o memory_info: A pointer to a block of memory to free for reuse.
%
*/
MagickExport MemoryInfo *RelinquishVirtualMemory(MemoryInfo *memory_info)
{
assert(memory_info != (MemoryInfo *) NULL);
assert(memory_info->signature == MagickCoreSignature);
if (memory_info->blob != (void *) NULL)
switch (memory_info->type)
{
case AlignedVirtualMemory:
{
memory_info->blob=RelinquishAlignedMemory(memory_info->blob);
break;
}
case MapVirtualMemory:
{
(void) UnmapBlob(memory_info->blob,memory_info->length);
memory_info->blob=NULL;
if (*memory_info->filename != '\0')
(void) RelinquishUniqueFileResource(memory_info->filename);
break;
}
case UnalignedVirtualMemory:
default:
{
memory_info->blob=RelinquishMagickMemory(memory_info->blob);
break;
}
}
memory_info->signature=(~MagickCoreSignature);
memory_info=(MemoryInfo *) RelinquishAlignedMemory(memory_info);
return(memory_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e s e t M a g i c k M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% 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
% updating the byte string. Most compilers will avoid optimizing away access
% to a volatile pointer, even if the pointer appears to be unused after the
% call.
%
% The format of the ResetMagickMemory method is:
%
% void *ResetMagickMemory(void *memory,int c,const size_t size)
%
% A description of each parameter follows:
%
% o memory: a pointer to a memory allocation.
%
% o c: set the memory to this value.
%
% o size: size of the memory to reset.
%
*/
MagickExport void *ResetMagickMemory(void *memory,int c,const size_t size)
{
volatile unsigned char
*p = (volatile unsigned char *) memory;
size_t
n = size;
assert(memory != (void *) NULL);
while (n-- != 0)
*p++=(unsigned char) c;
return(memory);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ R e s e t M a x M e m o r y R e q u e s t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ResetMaxMemoryRequest() resets the max_memory_request value.
%
% The format of the ResetMaxMemoryRequest method is:
%
% void ResetMaxMemoryRequest(void)
%
*/
MagickPrivate void ResetMaxMemoryRequest(void)
{
max_memory_request=0;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ 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 %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ResetVirtualAnonymousMemory() resets the virtual_anonymous_memory value.
%
% The format of the ResetVirtualAnonymousMemory method is:
%
% void ResetVirtualAnonymousMemory(void)
%
*/
MagickPrivate void ResetVirtualAnonymousMemory(void)
{
virtual_anonymous_memory=0;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e s i z e M a g i c k M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ResizeMagickMemory() changes the size of the memory and returns a pointer to
% the (possibly moved) block. The contents will be unchanged up to the
% lesser of the new and old sizes.
%
% The format of the ResizeMagickMemory method is:
%
% void *ResizeMagickMemory(void *memory,const size_t size)
%
% A description of each parameter follows:
%
% o memory: A pointer to a memory allocation.
%
% o size: the new size of the allocated memory.
%
*/
#if defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
static inline void *ResizeBlock(void *block,size_t size)
{
void
*memory;
if (block == (void *) NULL)
return(AcquireBlock(size));
memory=AcquireBlock(size);
if (memory == (void *) NULL)
return((void *) NULL);
if (size <= (SizeOfBlock(block)-sizeof(size_t)))
(void) memcpy(memory,block,size);
else
(void) memcpy(memory,block,SizeOfBlock(block)-sizeof(size_t));
memory_pool.allocation+=size;
return(memory);
}
#endif
MagickExport void *ResizeMagickMemory(void *memory,const size_t size)
{
void
*block;
if (memory == (void *) NULL)
return(AcquireMagickMemory(size));
#if !defined(MAGICKCORE_ANONYMOUS_MEMORY_SUPPORT)
block=memory_methods.resize_memory_handler(memory,size == 0 ? 1UL : size);
if (block == (void *) NULL)
memory=RelinquishMagickMemory(memory);
#else
LockSemaphoreInfo(memory_semaphore);
block=ResizeBlock(memory,size == 0 ? 1UL : size);
if (block == (void *) NULL)
{
if (ExpandHeap(size == 0 ? 1UL : size) == MagickFalse)
{
UnlockSemaphoreInfo(memory_semaphore);
memory=RelinquishMagickMemory(memory);
ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
}
block=ResizeBlock(memory,size == 0 ? 1UL : size);
assert(block != (void *) NULL);
}
UnlockSemaphoreInfo(memory_semaphore);
memory=RelinquishMagickMemory(memory);
#endif
return(block);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e s i z e Q u a n t u m M e m o r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ResizeQuantumMemory() changes the size of the memory and returns a pointer
% to the (possibly moved) block. The contents will be unchanged up to the
% lesser of the new and old sizes.
%
% The format of the ResizeQuantumMemory method is:
%
% void *ResizeQuantumMemory(void *memory,const size_t count,
% const size_t quantum)
%
% A description of each parameter follows:
%
% o memory: A pointer to a memory allocation.
%
% o count: the number of objects to allocate contiguously.
%
% o quantum: the size (in bytes) of each object.
%
*/
MagickExport void *ResizeQuantumMemory(void *memory,const size_t count,
const size_t quantum)
{
size_t
size;
if ((HeapOverflowSanityCheckGetSize(count,quantum,&size) != MagickFalse) ||
(size > GetMaxMemoryRequest()))
{
errno=ENOMEM;
memory=RelinquishMagickMemory(memory);
return(NULL);
}
return(ResizeMagickMemory(memory,size));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% 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 %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% SetMagickAlignedMemoryMethods() sets the methods to acquire and relinquish
% aligned memory.
%
% The format of the SetMagickAlignedMemoryMethods() method is:
%
% SetMagickAlignedMemoryMethods(
% AcquireAlignedMemoryHandler acquire_aligned_memory_handler,
% RelinquishAlignedMemoryHandler relinquish_aligned_memory_handler)
%
% A description of each parameter follows:
%
% o acquire_memory_handler: method to acquire aligned memory.
%
% o relinquish_aligned_memory_handler: method to relinquish aligned memory.
%
*/
MagickExport void SetMagickAlignedMemoryMethods(
AcquireAlignedMemoryHandler acquire_aligned_memory_handler,
RelinquishAlignedMemoryHandler relinquish_aligned_memory_handler)
{
memory_methods.acquire_aligned_memory_handler=acquire_aligned_memory_handler;
memory_methods.relinquish_aligned_memory_handler=
relinquish_aligned_memory_handler;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% S e t M a g i c k M e m o r y M e t h o d s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% SetMagickMemoryMethods() sets the methods to acquire, resize, and destroy
% memory. Your custom memory methods must be set prior to the
% MagickCoreGenesis() method.
%
% The format of the SetMagickMemoryMethods() method is:
%
% SetMagickMemoryMethods(AcquireMemoryHandler acquire_memory_handler,
% ResizeMemoryHandler resize_memory_handler,
% DestroyMemoryHandler destroy_memory_handler)
%
% A description of each parameter follows:
%
% o acquire_memory_handler: method to acquire memory (e.g. malloc).
%
% o resize_memory_handler: method to resize memory (e.g. realloc).
%
% o destroy_memory_handler: method to destroy memory (e.g. free).
%
*/
MagickExport void SetMagickMemoryMethods(
AcquireMemoryHandler acquire_memory_handler,
ResizeMemoryHandler resize_memory_handler,
DestroyMemoryHandler destroy_memory_handler)
{
/*
Set memory methods.
*/
if (acquire_memory_handler != (AcquireMemoryHandler) NULL)
memory_methods.acquire_memory_handler=acquire_memory_handler;
if (resize_memory_handler != (ResizeMemoryHandler) NULL)
memory_methods.resize_memory_handler=resize_memory_handler;
if (destroy_memory_handler != (DestroyMemoryHandler) NULL)
memory_methods.destroy_memory_handler=destroy_memory_handler;
}