Coverage Report

Created: 2026-06-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jasper/src/libjasper/base/jas_malloc.c
Line
Count
Source
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
402M
{
138
402M
  assert(jas_allocator);
139
402M
  void *result;
140
402M
  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
402M
  result = (jas_allocator->alloc)(jas_allocator, size ? size : 1);
145
402M
#endif
146
402M
  JAS_LOGDEBUGF(100, "jas_malloc(%zu) -> %p\n", size, result);
147
402M
  return result;
148
402M
}
149
150
JAS_EXPORT
151
void *jas_realloc(void *ptr, size_t size)
152
1.38M
{
153
1.38M
  assert(jas_allocator);
154
1.38M
  void *result;
155
1.38M
  JAS_LOGDEBUGF(101, "jas_realloc(%p, %zu)\n", ptr, size);
156
1.38M
  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
1.38M
  if (!ptr) {
161
1.29M
    if (size) {
162
      /* Handle a new allocation of nonzero size. */
163
1.29M
      result = (jas_allocator->alloc)(jas_allocator, size);
164
1.29M
      JAS_LOGDEBUGF(101, "jas_realloc: alloc(%p, %zu) -> %p\n",
165
1.29M
        jas_allocator, size, result);
166
1.29M
    } 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
1.29M
  } else {
178
96.9k
    result = (jas_allocator->realloc)(jas_allocator, ptr, size);
179
96.9k
    JAS_LOGDEBUGF(100, "jas_realloc: realloc(%p, %p, %zu) -> %p\n",
180
96.9k
      jas_allocator, ptr, size, result);
181
96.9k
  }
182
1.38M
  return result;
183
1.38M
}
184
185
JAS_EXPORT
186
void jas_free(void *ptr)
187
522M
{
188
522M
  assert(jas_allocator);
189
522M
  JAS_LOGDEBUGF(100, "jas_free(%p)\n", ptr);
190
522M
  (jas_allocator->free)(jas_allocator, ptr);
191
522M
}
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
193M
{
214
193M
  size_t size;
215
193M
  if (!jas_safe_size_mul(num_elements, element_size, &size)) {
216
0
    return 0;
217
0
  }
218
193M
  return jas_malloc(size);
219
193M
}
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
99.4k
{
233
99.4k
  size_t size;
234
99.4k
  if (!jas_safe_size_mul(num_elements, element_size, &size)) {
235
0
    return 0;
236
0
  }
237
99.4k
  return jas_realloc(ptr, size);
238
99.4k
}
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
807M
#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
403M
  ((sizeof(jas_mb_t) + sizeof(max_align_t) - 1) / sizeof(max_align_t))
320
403M
#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
403M
{
324
403M
  mb->magic = JAS_BMA_MAGIC;
325
403M
  mb->size = size;
326
403M
}
327
328
static void jas_mb_destroy(jas_mb_t *mb)
329
403M
{
330
403M
  mb->magic = 0;
331
403M
  mb->size = 0;
332
403M
}
333
334
static void *jas_mb_get_data(jas_mb_t *mb)
335
403M
{
336
403M
  assert(mb->magic == JAS_BMA_MAGIC);
337
403M
  return JAS_CAST(void *, JAS_CAST(max_align_t *, mb) + JAS_MB_ADJUST);
338
403M
}
339
340
static jas_mb_t *jas_get_mb(void *ptr)
341
403M
{
342
403M
  assert(ptr);
343
403M
  jas_mb_t *mb = JAS_CAST(jas_mb_t *,
344
403M
    JAS_CAST(max_align_t *, ptr) - JAS_MB_ADJUST);
345
403M
  assert(mb->magic == JAS_BMA_MAGIC);
346
  /* This is one check that I do not want disabled with NDEBUG. */
347
403M
  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
403M
  return mb;
353
403M
}
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
10
{
388
10
  allocator->base.cleanup = jas_basic_cleanup;
389
10
  allocator->base.alloc = jas_basic_alloc;
390
10
  allocator->base.free = jas_basic_free;
391
10
  allocator->base.realloc = jas_basic_realloc;
392
10
  allocator->delegate = delegate;
393
10
  assert(allocator->base.cleanup != delegate->cleanup);
394
10
  assert(allocator->base.alloc != delegate->alloc);
395
10
  assert(allocator->base.free != delegate->free);
396
10
  assert(allocator->base.realloc != delegate->realloc);
397
10
  allocator->max_mem = max_mem;
398
10
  allocator->mem = 0;
399
10
#if defined(JAS_THREADS)
400
10
  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
10
#endif
406
10
}
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
403M
{
424
403M
  void *result;
425
403M
  jas_mb_t *mb = 0;
426
403M
  size_t ext_size;
427
403M
  size_t mem;
428
403M
  jas_basic_allocator_t *a = JAS_CAST(jas_basic_allocator_t *, allocator);
429
403M
  bool has_lock = false;
430
431
403M
  JAS_CAST(void, has_lock); /* suppress warning about unused variable */
432
433
403M
  JAS_LOGDEBUGF(100, "jas_basic_alloc(%p, %zu)\n", allocator, size);
434
403M
  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
403M
  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
403M
#if defined(JAS_THREADS)
448
403M
  jas_mutex_lock(&a->mutex);
449
403M
  has_lock = true;
450
403M
#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
403M
  if (!jas_safe_size_add(a->mem, ext_size, &mem) || mem > a->max_mem) {
459
159
    jas_logerrorf("maximum memory limit (%zu) would be exceeded\n",
460
159
      a->max_mem);
461
159
    result = 0;
462
159
    goto done;
463
159
  }
464
465
  /*
466
  Perform the requested allocation using the delegated-to allocator.
467
  */
468
403M
  JAS_LOGDEBUGF(100, "jas_basic_alloc: alloc(%p, %zu)\n", a->delegate,
469
403M
    ext_size);
470
403M
  if ((mb = (a->delegate->alloc)(a->delegate, ext_size))) {
471
403M
    jas_mb_init(mb, ext_size);
472
403M
    result = jas_mb_get_data(mb);
473
403M
    a->mem = mem;
474
403M
  } else {
475
0
    result = 0;
476
0
  }
477
478
403M
done:
479
403M
#if defined(JAS_THREADS)
480
403M
  if (has_lock) {
481
403M
    jas_mutex_unlock(&a->mutex);
482
403M
  }
483
403M
#endif
484
485
403M
  JAS_LOGDEBUGF(99, "jas_basic_alloc(%p, %zu) -> %p (mb=%p)\n", allocator,
486
403M
    size, result, mb);
487
403M
  JAS_LOGDEBUGF(102, "max_mem=%zu; mem=%zu\n", a->max_mem, a->mem);
488
489
403M
  return result;
490
403M
}
491
492
JAS_EXPORT
493
void *jas_basic_realloc(jas_allocator_t *allocator, void *ptr, size_t size)
494
96.9k
{
495
96.9k
  void *result;
496
96.9k
  jas_mb_t *old_mb;
497
96.9k
  size_t old_ext_size;
498
96.9k
  jas_mb_t *mb = 0;
499
96.9k
  size_t ext_size;
500
96.9k
  size_t mem;
501
96.9k
  jas_basic_allocator_t *a = JAS_CAST(jas_basic_allocator_t *, allocator);
502
96.9k
  bool has_lock = false;
503
504
96.9k
  JAS_CAST(void, has_lock); /* suppress warning about unused variable */
505
506
96.9k
  JAS_LOGDEBUGF(100, "jas_basic_realloc(%p, %p, %zu)\n", allocator, ptr,
507
96.9k
    size);
508
  /*
509
  Check for a realloc operation that is equivalent to an alloc operation.
510
  */
511
96.9k
  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
96.9k
  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
96.9k
  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
96.9k
#if defined(JAS_THREADS)
538
96.9k
  jas_mutex_lock(&a->mutex);
539
96.9k
  has_lock = true;
540
96.9k
#endif
541
542
96.9k
  old_mb = jas_get_mb(ptr);
543
96.9k
  old_ext_size = old_mb->size;
544
96.9k
  JAS_LOGDEBUGF(101, "jas_basic_realloc: old_mb=%p; old_ext_size=%zu\n",
545
96.9k
    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
96.9k
  if (ext_size <= old_ext_size) {
551
0
    result = jas_mb_get_data(old_mb);
552
0
    goto done;
553
0
  }
554
555
96.9k
  if (!jas_safe_size_add(a->mem, ext_size - old_ext_size, &mem) ||
556
96.9k
    mem > a->max_mem) {
557
0
    jas_logerrorf("maximum memory limit (%zu) would be exceeded\n",
558
0
      a->max_mem);
559
0
    result = 0;
560
0
    goto done;
561
0
  }
562
563
96.9k
  JAS_LOGDEBUGF(100, "jas_basic_realloc: realloc(%p, %p, %zu)\n",
564
96.9k
    a->delegate, old_mb, ext_size);
565
96.9k
  jas_mb_destroy(old_mb);
566
96.9k
  if ((mb = (a->delegate->realloc)(a->delegate, old_mb, ext_size))) {
567
96.9k
    jas_mb_init(mb, ext_size);
568
96.9k
    result = jas_mb_get_data(mb);
569
96.9k
    a->mem = mem;
570
96.9k
  } else {
571
0
    jas_mb_init(old_mb, old_ext_size);
572
0
    result = 0;
573
0
  }
574
575
96.9k
done:
576
96.9k
#if defined(JAS_THREADS)
577
96.9k
  if (has_lock) {
578
96.9k
    jas_mutex_unlock(&a->mutex);
579
96.9k
  }
580
96.9k
#endif
581
582
96.9k
  JAS_LOGDEBUGF(100, "jas_basic_realloc(%p, %p, %zu) -> %p (%p)\n", allocator,
583
96.9k
    ptr, size, result, mb);
584
96.9k
  JAS_LOGDEBUGF(102, "max_mem=%zu; mem=%zu\n", a->max_mem, a->mem);
585
586
96.9k
  return result;
587
96.9k
}
588
589
JAS_EXPORT
590
void jas_basic_free(jas_allocator_t *allocator, void *ptr)
591
522M
{
592
522M
  jas_mb_t *mb;
593
522M
  size_t ext_size;
594
522M
  jas_basic_allocator_t *a = JAS_CAST(jas_basic_allocator_t *, allocator);
595
596
597
522M
  JAS_LOGDEBUGF(100, "jas_basic_free(%p)\n", ptr);
598
522M
  if (ptr) {
599
403M
#if defined(JAS_THREADS)
600
403M
    jas_mutex_lock(&a->mutex);
601
403M
#endif
602
403M
    mb = jas_get_mb(ptr);
603
403M
    ext_size = mb->size;
604
403M
    JAS_LOGDEBUGF(101, "jas_basic_free(%p, %p) (mb=%p; ext_size=%zu)\n",
605
403M
      allocator, ptr, mb, ext_size);
606
403M
    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
403M
    JAS_LOGDEBUGF(100, "jas_basic_free: free(%p, %p)\n", a->delegate, mb);
614
403M
    jas_mb_destroy(mb);
615
403M
    (a->delegate->free)(a->delegate, mb);
616
403M
#if defined(JAS_THREADS)
617
403M
    jas_mutex_unlock(&a->mutex);
618
403M
#endif
619
403M
  }
620
522M
  JAS_LOGDEBUGF(102, "max_mem=%zu; mem=%zu\n", a->max_mem, a->mem);
621
622
522M
}
623
624
/******************************************************************************\
625
\******************************************************************************/
626
627
size_t jas_get_total_mem_size()
628
20
{
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
20
  if (sysinfo(&buf)) {
640
0
    return 0;
641
0
  }
642
20
  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
20
}