/src/jasper/src/libjasper/base/jas_malloc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 1999-2000 Image Power, Inc. and the University of |
3 | | * British Columbia. |
4 | | * Copyright (c) 2001-2002 Michael David Adams. |
5 | | * All rights reserved. |
6 | | */ |
7 | | |
8 | | /* __START_OF_JASPER_LICENSE__ |
9 | | * |
10 | | * JasPer License Version 2.0 |
11 | | * |
12 | | * Copyright (c) 2001-2006 Michael David Adams |
13 | | * Copyright (c) 1999-2000 Image Power, Inc. |
14 | | * Copyright (c) 1999-2000 The University of British Columbia |
15 | | * |
16 | | * All rights reserved. |
17 | | * |
18 | | * Permission is hereby granted, free of charge, to any person (the |
19 | | * "User") obtaining a copy of this software and associated documentation |
20 | | * files (the "Software"), to deal in the Software without restriction, |
21 | | * including without limitation the rights to use, copy, modify, merge, |
22 | | * publish, distribute, and/or sell copies of the Software, and to permit |
23 | | * persons to whom the Software is furnished to do so, subject to the |
24 | | * following conditions: |
25 | | * |
26 | | * 1. The above copyright notices and this permission notice (which |
27 | | * includes the disclaimer below) shall be included in all copies or |
28 | | * substantial portions of the Software. |
29 | | * |
30 | | * 2. The name of a copyright holder shall not be used to endorse or |
31 | | * promote products derived from the Software without specific prior |
32 | | * written permission. |
33 | | * |
34 | | * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS |
35 | | * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
36 | | * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS |
37 | | * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING |
38 | | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
39 | | * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO |
40 | | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL |
41 | | * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING |
42 | | * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
43 | | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION |
44 | | * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE |
45 | | * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE |
46 | | * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. |
47 | | * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS |
48 | | * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL |
49 | | * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS |
50 | | * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE |
51 | | * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE |
52 | | * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL |
53 | | * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, |
54 | | * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL |
55 | | * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH |
56 | | * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, |
57 | | * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH |
58 | | * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY |
59 | | * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. |
60 | | * |
61 | | * __END_OF_JASPER_LICENSE__ |
62 | | */ |
63 | | |
64 | | /* |
65 | | * Memory Allocator |
66 | | * |
67 | | * $Id$ |
68 | | */ |
69 | | |
70 | | /******************************************************************************\ |
71 | | * Includes. |
72 | | \******************************************************************************/ |
73 | | |
74 | | #define JAS_FOR_INTERNAL_USE_ONLY |
75 | | |
76 | | #include "jasper/jas_types.h" |
77 | | #include "jasper/jas_malloc.h" |
78 | | #include "jasper/jas_debug.h" |
79 | | #include "jasper/jas_math.h" |
80 | | |
81 | | #include <stdio.h> |
82 | | #include <stdlib.h> |
83 | | #include <stddef.h> |
84 | | |
85 | | /* We need the prototype for memset. */ |
86 | | #include <string.h> |
87 | | |
88 | | #if defined(__linux__) |
89 | | # include <sys/sysinfo.h> |
90 | | #elif defined(__APPLE__) |
91 | | # include <sys/types.h> |
92 | | # include <sys/sysctl.h> |
93 | | #elif defined(__unix__) && (!defined(__linux__) && !defined(__APPLE__)) |
94 | | # include <unistd.h> |
95 | | #elif defined(_WIN32) |
96 | | # include <windows.h> |
97 | | # include <sysinfoapi.h> |
98 | | #endif |
99 | | |
100 | | /******************************************************************************\ |
101 | | * Data. |
102 | | \******************************************************************************/ |
103 | | |
104 | | /* MUTABLE_SHARED_STATE_TAG: This is mutable shared state. */ |
105 | | /* The memory allocator object to be used for all memory allocation. */ |
106 | | jas_allocator_t *jas_allocator = 0; |
107 | | |
108 | | /* MUTABLE_SHARED_STATE_TAG: This is mutable shared state. */ |
109 | | jas_std_allocator_t jas_std_allocator = { |
110 | | .base = { |
111 | | .cleanup = 0, |
112 | | .alloc = 0, |
113 | | .free = 0, |
114 | | .realloc = 0, |
115 | | }, |
116 | | }; |
117 | | |
118 | | /* MUTABLE_SHARED_STATE_TAG: This is mutable shared state. */ |
119 | | jas_basic_allocator_t jas_basic_allocator = { |
120 | | .base = { |
121 | | .cleanup = 0, |
122 | | .alloc = 0, |
123 | | .free = 0, |
124 | | .realloc = 0, |
125 | | }, |
126 | | .delegate = 0, |
127 | | .mem = 0, |
128 | | .max_mem = 0, |
129 | | }; |
130 | | |
131 | | /******************************************************************************\ |
132 | | * Basic memory allocation and deallocation primitives. |
133 | | \******************************************************************************/ |
134 | | |
135 | | JAS_EXPORT |
136 | | void *jas_malloc(size_t size) |
137 | 14.8M | { |
138 | 14.8M | assert(jas_allocator); |
139 | 14.8M | void *result; |
140 | 14.8M | JAS_LOGDEBUGF(101, "jas_malloc(%zu)\n", size); |
141 | | #if defined(JAS_MALLOC_RETURN_NULL_PTR_FOR_ZERO_SIZE) |
142 | | result = size ? (jas_allocator->alloc)(jas_allocator, size) : 0; |
143 | | #else |
144 | 14.8M | result = (jas_allocator->alloc)(jas_allocator, size ? size : 1); |
145 | 14.8M | #endif |
146 | 14.8M | JAS_LOGDEBUGF(100, "jas_malloc(%zu) -> %p\n", size, result); |
147 | 14.8M | return result; |
148 | 14.8M | } |
149 | | |
150 | | JAS_EXPORT |
151 | | void *jas_realloc(void *ptr, size_t size) |
152 | 24.5k | { |
153 | 24.5k | assert(jas_allocator); |
154 | 24.5k | void *result; |
155 | 24.5k | JAS_LOGDEBUGF(101, "jas_realloc(%p, %zu)\n", ptr, size); |
156 | 24.5k | if (!size) { |
157 | 0 | jas_logwarnf("warning: zero size reallocations are unwise " |
158 | 0 | "(and have undefined behavior as of C23)\n"); |
159 | 0 | } |
160 | 24.5k | if (!ptr) { |
161 | 19.4k | if (size) { |
162 | | /* Handle a new allocation of nonzero size. */ |
163 | 19.4k | result = (jas_allocator->alloc)(jas_allocator, size); |
164 | 19.4k | JAS_LOGDEBUGF(101, "jas_realloc: alloc(%p, %zu) -> %p\n", |
165 | 19.4k | jas_allocator, size, result); |
166 | 19.4k | } else { |
167 | | /* Handle a new allocation of zero size. */ |
168 | | #if defined(JAS_MALLOC_RETURN_NULL_PTR_FOR_ZERO_SIZE) |
169 | | result = 0; |
170 | | JAS_LOGDEBUGF(101, "jas_realloc: no-op -> %p\n", result); |
171 | | #else |
172 | 0 | result = (jas_allocator->alloc)(jas_allocator, 1); |
173 | 0 | JAS_LOGDEBUGF(101, "jas_realloc: alloc(%p, %p, %zu) -> %p\n", |
174 | 0 | jas_allocator, ptr, size, result); |
175 | 0 | #endif |
176 | 0 | } |
177 | 19.4k | } else { |
178 | 5.06k | result = (jas_allocator->realloc)(jas_allocator, ptr, size); |
179 | 5.06k | JAS_LOGDEBUGF(100, "jas_realloc: realloc(%p, %p, %zu) -> %p\n", |
180 | 5.06k | jas_allocator, ptr, size, result); |
181 | 5.06k | } |
182 | 24.5k | return result; |
183 | 24.5k | } |
184 | | |
185 | | JAS_EXPORT |
186 | | void jas_free(void *ptr) |
187 | 15.3M | { |
188 | 15.3M | assert(jas_allocator); |
189 | 15.3M | JAS_LOGDEBUGF(100, "jas_free(%p)\n", ptr); |
190 | 15.3M | (jas_allocator->free)(jas_allocator, ptr); |
191 | 15.3M | } |
192 | | |
193 | | /******************************************************************************\ |
194 | | * Additional memory allocation and deallocation primitives |
195 | | * (mainly for overflow checking). |
196 | | \******************************************************************************/ |
197 | | |
198 | | void *jas_calloc(size_t num_elements, size_t element_size) |
199 | 0 | { |
200 | 0 | void *ptr; |
201 | 0 | size_t size; |
202 | 0 | if (!jas_safe_size_mul(num_elements, element_size, &size)) { |
203 | 0 | return 0; |
204 | 0 | } |
205 | 0 | if (!(ptr = jas_malloc(size))) { |
206 | 0 | return 0; |
207 | 0 | } |
208 | 0 | memset(ptr, 0, size); |
209 | 0 | return ptr; |
210 | 0 | } |
211 | | |
212 | | void *jas_alloc2(size_t num_elements, size_t element_size) |
213 | 1.84M | { |
214 | 1.84M | size_t size; |
215 | 1.84M | if (!jas_safe_size_mul(num_elements, element_size, &size)) { |
216 | 0 | return 0; |
217 | 0 | } |
218 | 1.84M | return jas_malloc(size); |
219 | 1.84M | } |
220 | | |
221 | | void *jas_alloc3(size_t num_arrays, size_t array_size, size_t element_size) |
222 | 0 | { |
223 | 0 | size_t size; |
224 | 0 | if (!jas_safe_size_mul(array_size, element_size, &size) || |
225 | 0 | !jas_safe_size_mul(size, num_arrays, &size)) { |
226 | 0 | return 0; |
227 | 0 | } |
228 | 0 | return jas_malloc(size); |
229 | 0 | } |
230 | | |
231 | | void *jas_realloc2(void *ptr, size_t num_elements, size_t element_size) |
232 | 5.14k | { |
233 | 5.14k | size_t size; |
234 | 5.14k | if (!jas_safe_size_mul(num_elements, element_size, &size)) { |
235 | 0 | return 0; |
236 | 0 | } |
237 | 5.14k | return jas_realloc(ptr, size); |
238 | 5.14k | } |
239 | | |
240 | | /******************************************************************************\ |
241 | | \******************************************************************************/ |
242 | | |
243 | | JAS_EXPORT |
244 | | void jas_allocator_cleanup(jas_allocator_t *allocator) |
245 | 0 | { |
246 | 0 | if (allocator->cleanup) { |
247 | 0 | (allocator->cleanup)(allocator); |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | /******************************************************************************\ |
252 | | \******************************************************************************/ |
253 | | |
254 | | JAS_EXPORT |
255 | | void *jas_std_alloc(jas_allocator_t *allocator, size_t size); |
256 | | JAS_EXPORT |
257 | | void *jas_std_realloc(jas_allocator_t *allocator, void *ptr, size_t size); |
258 | | JAS_EXPORT |
259 | | void jas_std_free(jas_allocator_t *allocator, void *ptr); |
260 | | |
261 | | JAS_EXPORT |
262 | | void jas_std_allocator_init(jas_std_allocator_t *allocator) |
263 | 0 | { |
264 | 0 | JAS_CAST(void, allocator); |
265 | 0 | allocator->base.cleanup = 0; |
266 | 0 | allocator->base.alloc = jas_std_alloc; |
267 | 0 | allocator->base.free = jas_std_free; |
268 | 0 | allocator->base.realloc = jas_std_realloc; |
269 | 0 | } |
270 | | |
271 | | JAS_EXPORT |
272 | | void *jas_std_alloc(jas_allocator_t *allocator, size_t size) |
273 | 0 | { |
274 | 0 | JAS_CAST(void, allocator); |
275 | 0 | JAS_LOGDEBUGF(111, "jas_std_alloc(%zu)\n", size); |
276 | 0 | void* result = malloc(size); |
277 | 0 | JAS_LOGDEBUGF(110, "jas_std_alloc(%zu) -> %p\n", size, result); |
278 | 0 | return result; |
279 | 0 | } |
280 | | |
281 | | JAS_EXPORT |
282 | | void *jas_std_realloc(jas_allocator_t *allocator, void *ptr, size_t size) |
283 | 0 | { |
284 | 0 | JAS_CAST(void, allocator); |
285 | 0 | JAS_LOGDEBUGF(111, "jas_std_realloc(%p, %zu)\n", allocator, size); |
286 | 0 | void *result = realloc(ptr, size); |
287 | 0 | JAS_LOGDEBUGF(110, "jas_std_realloc(%zu) -> %p\n", size, result); |
288 | 0 | return result; |
289 | 0 | } |
290 | | |
291 | | JAS_EXPORT |
292 | | void jas_std_free(jas_allocator_t *allocator, void *ptr) |
293 | 0 | { |
294 | 0 | JAS_CAST(void, allocator); |
295 | 0 | JAS_LOGDEBUGF(111, "jas_std_free(%p, %p)\n", allocator, ptr); |
296 | 0 | free(ptr); |
297 | 0 | } |
298 | | |
299 | | /******************************************************************************\ |
300 | | \******************************************************************************/ |
301 | | |
302 | | JAS_EXPORT |
303 | | void *jas_basic_alloc(jas_allocator_t *allocator, size_t size); |
304 | | JAS_EXPORT |
305 | | void *jas_basic_realloc(jas_allocator_t *allocator, void *ptr, size_t size); |
306 | | JAS_EXPORT |
307 | | void jas_basic_free(jas_allocator_t *allocator, void *ptr); |
308 | | JAS_EXPORT |
309 | | void jas_basic_cleanup(jas_allocator_t *allocator); |
310 | | |
311 | 29.7M | #define JAS_BMA_MAGIC 0xdeadbeefULL |
312 | | |
313 | | typedef struct { |
314 | | unsigned long long magic; |
315 | | size_t size; |
316 | | } jas_mb_t; |
317 | | |
318 | | #define JAS_MB_ADJUST \ |
319 | 14.8M | ((sizeof(jas_mb_t) + sizeof(max_align_t) - 1) / sizeof(max_align_t)) |
320 | 14.8M | #define JAS_MB_SIZE (JAS_MB_ADJUST * sizeof(max_align_t)) |
321 | | |
322 | | static void jas_mb_init(jas_mb_t *mb, size_t size) |
323 | 14.8M | { |
324 | 14.8M | mb->magic = JAS_BMA_MAGIC; |
325 | 14.8M | mb->size = size; |
326 | 14.8M | } |
327 | | |
328 | | static void jas_mb_destroy(jas_mb_t *mb) |
329 | 14.8M | { |
330 | 14.8M | mb->magic = 0; |
331 | 14.8M | mb->size = 0; |
332 | 14.8M | } |
333 | | |
334 | | static void *jas_mb_get_data(jas_mb_t *mb) |
335 | 14.8M | { |
336 | 14.8M | assert(mb->magic == JAS_BMA_MAGIC); |
337 | 14.8M | return JAS_CAST(void *, JAS_CAST(max_align_t *, mb) + JAS_MB_ADJUST); |
338 | 14.8M | } |
339 | | |
340 | | static jas_mb_t *jas_get_mb(void *ptr) |
341 | 14.8M | { |
342 | 14.8M | assert(ptr); |
343 | 14.8M | jas_mb_t *mb = JAS_CAST(jas_mb_t *, |
344 | 14.8M | JAS_CAST(max_align_t *, ptr) - JAS_MB_ADJUST); |
345 | 14.8M | assert(mb->magic == JAS_BMA_MAGIC); |
346 | | /* This is one check that I do not want disabled with NDEBUG. */ |
347 | 14.8M | if (mb->magic != JAS_BMA_MAGIC) { |
348 | | /* This line of code should never be reached. */ |
349 | 0 | assert(0); |
350 | 0 | abort(); |
351 | 0 | } |
352 | 14.8M | return mb; |
353 | 14.8M | } |
354 | | |
355 | | void jas_set_max_mem_usage(size_t max_mem) |
356 | 0 | { |
357 | 0 | assert(jas_allocator == JAS_CAST(jas_allocator_t*, &jas_basic_allocator)); |
358 | 0 | jas_basic_allocator_t *allocator = JAS_CAST(jas_basic_allocator_t *, |
359 | 0 | jas_allocator); |
360 | 0 | #if defined(JAS_THREADS) |
361 | 0 | jas_mutex_lock(&allocator->mutex); |
362 | 0 | #endif |
363 | 0 | allocator->max_mem = (!max_mem || allocator->mem <= max_mem) ? max_mem : |
364 | 0 | allocator->mem; |
365 | 0 | #if defined(JAS_THREADS) |
366 | 0 | jas_mutex_unlock(&allocator->mutex); |
367 | 0 | #endif |
368 | 0 | } |
369 | | |
370 | | size_t jas_get_mem_usage() |
371 | 0 | { |
372 | 0 | assert(jas_allocator == JAS_CAST(jas_allocator_t*, &jas_basic_allocator)); |
373 | 0 | jas_basic_allocator_t *allocator = JAS_CAST(jas_basic_allocator_t *, |
374 | 0 | jas_allocator); |
375 | 0 | #if defined(JAS_THREADS) |
376 | 0 | jas_mutex_lock(&allocator->mutex); |
377 | 0 | #endif |
378 | 0 | size_t result = allocator->mem; |
379 | 0 | #if defined(JAS_THREADS) |
380 | 0 | jas_mutex_unlock(&allocator->mutex); |
381 | 0 | #endif |
382 | 0 | return result; |
383 | 0 | } |
384 | | |
385 | | void jas_basic_allocator_init(jas_basic_allocator_t *allocator, |
386 | | jas_allocator_t *delegate, size_t max_mem) |
387 | 9 | { |
388 | 9 | allocator->base.cleanup = jas_basic_cleanup; |
389 | 9 | allocator->base.alloc = jas_basic_alloc; |
390 | 9 | allocator->base.free = jas_basic_free; |
391 | 9 | allocator->base.realloc = jas_basic_realloc; |
392 | 9 | allocator->delegate = delegate; |
393 | 9 | assert(allocator->base.cleanup != delegate->cleanup); |
394 | 9 | assert(allocator->base.alloc != delegate->alloc); |
395 | 9 | assert(allocator->base.free != delegate->free); |
396 | 9 | assert(allocator->base.realloc != delegate->realloc); |
397 | 9 | allocator->max_mem = max_mem; |
398 | 9 | allocator->mem = 0; |
399 | 9 | #if defined(JAS_THREADS) |
400 | 9 | if (jas_mutex_init(&allocator->mutex)) { |
401 | | /* This line of code should never be reached. */ |
402 | 0 | assert(0); |
403 | 0 | abort(); |
404 | 0 | } |
405 | 9 | #endif |
406 | 9 | } |
407 | | |
408 | | JAS_EXPORT |
409 | | void jas_basic_cleanup(jas_allocator_t *allocator) |
410 | 0 | { |
411 | 0 | jas_basic_allocator_t *a = JAS_CAST(jas_basic_allocator_t *, |
412 | 0 | allocator); |
413 | 0 | if (a->delegate->cleanup) { |
414 | 0 | (a->delegate->cleanup)(allocator); |
415 | 0 | } |
416 | 0 | #if defined(JAS_THREADS) |
417 | 0 | jas_mutex_cleanup(&a->mutex); |
418 | 0 | #endif |
419 | 0 | } |
420 | | |
421 | | JAS_EXPORT |
422 | | void *jas_basic_alloc(jas_allocator_t *allocator, size_t size) |
423 | 14.8M | { |
424 | 14.8M | void *result; |
425 | 14.8M | jas_mb_t *mb = 0; |
426 | 14.8M | size_t ext_size; |
427 | 14.8M | size_t mem; |
428 | 14.8M | jas_basic_allocator_t *a = JAS_CAST(jas_basic_allocator_t *, allocator); |
429 | 14.8M | bool has_lock = false; |
430 | | |
431 | 14.8M | JAS_CAST(void, has_lock); /* suppress warning about unused variable */ |
432 | | |
433 | 14.8M | JAS_LOGDEBUGF(100, "jas_basic_alloc(%p, %zu)\n", allocator, size); |
434 | 14.8M | JAS_LOGDEBUGF(102, "max_mem=%zu; mem=%zu\n", a->max_mem, a->mem); |
435 | | #if defined(JAS_MALLOC_RETURN_NULL_PTR_FOR_ZERO_SIZE) |
436 | | if (!size) { |
437 | | result = 0; |
438 | | goto done; |
439 | | } |
440 | | #endif |
441 | 14.8M | if (!jas_safe_size_add(size, JAS_MB_SIZE, &ext_size)) { |
442 | 0 | jas_logerrorf("requested memory size is too large (%zu)\n", size); |
443 | 0 | result = 0; |
444 | 0 | goto done; |
445 | 0 | } |
446 | | |
447 | 14.8M | #if defined(JAS_THREADS) |
448 | 14.8M | jas_mutex_lock(&a->mutex); |
449 | 14.8M | has_lock = true; |
450 | 14.8M | #endif |
451 | | |
452 | | /* |
453 | | Calculate the amount of memory that would be allocated after the requested |
454 | | allocation is performed, being careful to ensure that this computation |
455 | | does not cause overflow. Then, ensure that the computed value does not |
456 | | exceed the memory usage limit. |
457 | | */ |
458 | 14.8M | if (!jas_safe_size_add(a->mem, ext_size, &mem) || mem > a->max_mem) { |
459 | 1 | jas_logerrorf("maximum memory limit (%zu) would be exceeded\n", |
460 | 1 | a->max_mem); |
461 | 1 | result = 0; |
462 | 1 | goto done; |
463 | 1 | } |
464 | | |
465 | | /* |
466 | | Perform the requested allocation using the delegated-to allocator. |
467 | | */ |
468 | 14.8M | JAS_LOGDEBUGF(100, "jas_basic_alloc: alloc(%p, %zu)\n", a->delegate, |
469 | 14.8M | ext_size); |
470 | 14.8M | if ((mb = (a->delegate->alloc)(a->delegate, ext_size))) { |
471 | 14.8M | jas_mb_init(mb, ext_size); |
472 | 14.8M | result = jas_mb_get_data(mb); |
473 | 14.8M | a->mem = mem; |
474 | 14.8M | } else { |
475 | 0 | result = 0; |
476 | 0 | } |
477 | | |
478 | 14.8M | done: |
479 | 14.8M | #if defined(JAS_THREADS) |
480 | 14.8M | if (has_lock) { |
481 | 14.8M | jas_mutex_unlock(&a->mutex); |
482 | 14.8M | } |
483 | 14.8M | #endif |
484 | | |
485 | 14.8M | JAS_LOGDEBUGF(99, "jas_basic_alloc(%p, %zu) -> %p (mb=%p)\n", allocator, |
486 | 14.8M | size, result, mb); |
487 | 14.8M | JAS_LOGDEBUGF(102, "max_mem=%zu; mem=%zu\n", a->max_mem, a->mem); |
488 | | |
489 | 14.8M | return result; |
490 | 14.8M | } |
491 | | |
492 | | JAS_EXPORT |
493 | | void *jas_basic_realloc(jas_allocator_t *allocator, void *ptr, size_t size) |
494 | 5.06k | { |
495 | 5.06k | void *result; |
496 | 5.06k | jas_mb_t *old_mb; |
497 | 5.06k | size_t old_ext_size; |
498 | 5.06k | jas_mb_t *mb = 0; |
499 | 5.06k | size_t ext_size; |
500 | 5.06k | size_t mem; |
501 | 5.06k | jas_basic_allocator_t *a = JAS_CAST(jas_basic_allocator_t *, allocator); |
502 | 5.06k | bool has_lock = false; |
503 | | |
504 | 5.06k | JAS_CAST(void, has_lock); /* suppress warning about unused variable */ |
505 | | |
506 | 5.06k | JAS_LOGDEBUGF(100, "jas_basic_realloc(%p, %p, %zu)\n", allocator, ptr, |
507 | 5.06k | size); |
508 | | /* |
509 | | Check for a realloc operation that is equivalent to an alloc operation. |
510 | | */ |
511 | 5.06k | if (!ptr) { |
512 | 0 | result = jas_basic_alloc(allocator, size); |
513 | 0 | goto done; |
514 | 0 | } |
515 | | /* |
516 | | Check for a realloc operation that is equivalent to a zero-sized |
517 | | allocation/reallocation. |
518 | | */ |
519 | 5.06k | if (ptr && !size) { |
520 | | #if defined(JAS_MALLOC_RETURN_NULL_PTR_FOR_ZERO_SIZE) |
521 | | jas_basic_free(allocator, ptr); |
522 | | result = 0; |
523 | | #else |
524 | 0 | if ((result = jas_basic_alloc(allocator, 1))) { |
525 | 0 | jas_basic_free(allocator, ptr); |
526 | 0 | } |
527 | 0 | #endif |
528 | 0 | goto done; |
529 | 0 | } |
530 | | |
531 | 5.06k | if (!jas_safe_size_add(size, JAS_MB_SIZE, &ext_size)) { |
532 | 0 | jas_logerrorf("requested memory size is too large (%zu)\n", size); |
533 | 0 | result = 0; |
534 | 0 | goto done; |
535 | 0 | } |
536 | | |
537 | 5.06k | #if defined(JAS_THREADS) |
538 | 5.06k | jas_mutex_lock(&a->mutex); |
539 | 5.06k | has_lock = true; |
540 | 5.06k | #endif |
541 | | |
542 | 5.06k | old_mb = jas_get_mb(ptr); |
543 | 5.06k | old_ext_size = old_mb->size; |
544 | 5.06k | JAS_LOGDEBUGF(101, "jas_basic_realloc: old_mb=%p; old_ext_size=%zu\n", |
545 | 5.06k | old_mb, old_ext_size); |
546 | | /* |
547 | | Skip performing any allocation if the currently-allocated block is |
548 | | sufficiently large to accommodate the allocation request. |
549 | | */ |
550 | 5.06k | if (ext_size <= old_ext_size) { |
551 | 0 | result = jas_mb_get_data(old_mb); |
552 | 0 | goto done; |
553 | 0 | } |
554 | | |
555 | 5.06k | if (!jas_safe_size_add(a->mem, ext_size - old_ext_size, &mem) || |
556 | 5.06k | mem > a->max_mem) { |
557 | 6 | jas_logerrorf("maximum memory limit (%zu) would be exceeded\n", |
558 | 6 | a->max_mem); |
559 | 6 | result = 0; |
560 | 6 | goto done; |
561 | 6 | } |
562 | | |
563 | 5.06k | JAS_LOGDEBUGF(100, "jas_basic_realloc: realloc(%p, %p, %zu)\n", |
564 | 5.06k | a->delegate, old_mb, ext_size); |
565 | 5.06k | jas_mb_destroy(old_mb); |
566 | 5.06k | if ((mb = (a->delegate->realloc)(a->delegate, old_mb, ext_size))) { |
567 | 5.06k | jas_mb_init(mb, ext_size); |
568 | 5.06k | result = jas_mb_get_data(mb); |
569 | 5.06k | a->mem = mem; |
570 | 5.06k | } else { |
571 | 0 | jas_mb_init(old_mb, old_ext_size); |
572 | 0 | result = 0; |
573 | 0 | } |
574 | | |
575 | 5.06k | done: |
576 | 5.06k | #if defined(JAS_THREADS) |
577 | 5.06k | if (has_lock) { |
578 | 5.06k | jas_mutex_unlock(&a->mutex); |
579 | 5.06k | } |
580 | 5.06k | #endif |
581 | | |
582 | 5.06k | JAS_LOGDEBUGF(100, "jas_basic_realloc(%p, %p, %zu) -> %p (%p)\n", allocator, |
583 | 5.06k | ptr, size, result, mb); |
584 | 5.06k | JAS_LOGDEBUGF(102, "max_mem=%zu; mem=%zu\n", a->max_mem, a->mem); |
585 | | |
586 | 5.06k | return result; |
587 | 5.06k | } |
588 | | |
589 | | JAS_EXPORT |
590 | | void jas_basic_free(jas_allocator_t *allocator, void *ptr) |
591 | 15.3M | { |
592 | 15.3M | jas_mb_t *mb; |
593 | 15.3M | size_t ext_size; |
594 | 15.3M | jas_basic_allocator_t *a = JAS_CAST(jas_basic_allocator_t *, allocator); |
595 | | |
596 | | |
597 | 15.3M | JAS_LOGDEBUGF(100, "jas_basic_free(%p)\n", ptr); |
598 | 15.3M | if (ptr) { |
599 | 14.8M | #if defined(JAS_THREADS) |
600 | 14.8M | jas_mutex_lock(&a->mutex); |
601 | 14.8M | #endif |
602 | 14.8M | mb = jas_get_mb(ptr); |
603 | 14.8M | ext_size = mb->size; |
604 | 14.8M | JAS_LOGDEBUGF(101, "jas_basic_free(%p, %p) (mb=%p; ext_size=%zu)\n", |
605 | 14.8M | allocator, ptr, mb, ext_size); |
606 | 14.8M | if (!jas_safe_size_sub(a->mem, ext_size, &a->mem)) { |
607 | 0 | jas_logerrorf("heap corruption detected (%zu exceeds %zu)\n", |
608 | 0 | ext_size, a->mem); |
609 | | /* This line of code should never be reached. */ |
610 | 0 | assert(0); |
611 | 0 | abort(); |
612 | 0 | } |
613 | 14.8M | JAS_LOGDEBUGF(100, "jas_basic_free: free(%p, %p)\n", a->delegate, mb); |
614 | 14.8M | jas_mb_destroy(mb); |
615 | 14.8M | (a->delegate->free)(a->delegate, mb); |
616 | 14.8M | #if defined(JAS_THREADS) |
617 | 14.8M | jas_mutex_unlock(&a->mutex); |
618 | 14.8M | #endif |
619 | 14.8M | } |
620 | 15.3M | JAS_LOGDEBUGF(102, "max_mem=%zu; mem=%zu\n", a->max_mem, a->mem); |
621 | | |
622 | 15.3M | } |
623 | | |
624 | | /******************************************************************************\ |
625 | | \******************************************************************************/ |
626 | | |
627 | | size_t jas_get_total_mem_size() |
628 | 18 | { |
629 | | #if defined(JAS_WASI_LIBC) |
630 | | /* |
631 | | NOTE: On the 32-bit WebAssembly platform, the unsigned integral type |
632 | | size_t is likely to have a size of 32 bits. So, choose the maximum |
633 | | memory to be less than 2 ^ 32 in order to avoid overflow. |
634 | | */ |
635 | | return JAS_CAST(size_t, 4096) * JAS_CAST(size_t, 1024) * |
636 | | JAS_CAST(size_t, 1024) - 1; |
637 | | #elif defined(__linux__) |
638 | | struct sysinfo buf; |
639 | 18 | if (sysinfo(&buf)) { |
640 | 0 | return 0; |
641 | 0 | } |
642 | 18 | return buf.totalram * buf.mem_unit; |
643 | | #elif defined(__APPLE__) |
644 | | int mib[] = {CTL_HW, HW_MEMSIZE}; |
645 | | uint64_t value = 0; |
646 | | size_t length = sizeof(value); |
647 | | if (sysctl(mib, 2, &value, &length, 0, 0)) { |
648 | | return 0; |
649 | | } |
650 | | return JAS_CAST(size_t, value); |
651 | | #elif defined(__unix__) && (!defined(__linux__) && !defined(__APPLE__) && !defined(__DJGPP__)) |
652 | | /* |
653 | | Reference: |
654 | | https://stackoverflow.com/questions/2513505/how-to-get-available-memory-c-g |
655 | | */ |
656 | | long pages = sysconf(_SC_PHYS_PAGES); |
657 | | long page_size = sysconf(_SC_PAGE_SIZE); |
658 | | return pages * page_size; |
659 | | #elif defined(_WIN32) |
660 | | /* |
661 | | Reference: |
662 | | https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getphysicallyinstalledsystemmemory |
663 | | */ |
664 | | ULONGLONG mem_size_in_kb; |
665 | | if (!GetPhysicallyInstalledSystemMemory(&mem_size_in_kb)) { |
666 | | return 0; |
667 | | } |
668 | | return (mem_size_in_kb < SIZE_MAX / JAS_CAST(size_t, 1024)) ? |
669 | | JAS_CAST(size_t, 1024) * mem_size_in_kb : SIZE_MAX; |
670 | | #else |
671 | | return 0; |
672 | | #endif |
673 | 18 | } |