Coverage Report

Created: 2025-08-11 08:01

/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
}