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