Coverage Report

Created: 2026-07-25 07:06

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