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