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