• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

saitoha / libsixel / 19339450837

13 Nov 2025 05:01PM UTC coverage: 43.831% (-0.3%) from 44.162%
19339450837

push

github

saitoha
build: guard metadata probe on platforms without fork

8298 of 28238 branches covered (29.39%)

11836 of 27004 relevant lines covered (43.83%)

991518.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.69
/src/allocator.c
1
/*
2
 * Copyright (c) 2021-2025 libsixel developers. See `AUTHORS`.
3
 * Copyright (c) 2014-2018 Hayaki Saito
4
 *
5
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6
 * this software and associated documentation files (the "Software"), to deal in
7
 * the Software without restriction, including without limitation the rights to
8
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
 * the Software, and to permit persons to whom the Software is furnished to do so,
10
 * subject to the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be included in all
13
 * copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
 */
22

23
#include "config.h"
24

25
/* STDC_HEADERS */
26
#include <stdlib.h>
27

28
#if HAVE_ASSERT_H
29
# include <assert.h>
30
#endif  /* HAVE_ASSERT_H */
31
#if HAVE_SYS_TYPES_H
32
# include <sys/types.h>
33
#endif  /* HAVE_SYS_TYPES_H */
34
#if HAVE_ERRNO_H
35
# include <errno.h>
36
#endif  /* HAVE_ERRNO_H */
37
#if HAVE_MEMORY_H
38
# include <memory.h>
39
#endif  /* HAVE_MEMORY_H */
40

41
#include "allocator.h"
42
#include "malloc_stub.h"
43
#include "sixel_atomic.h"
44

45
/* create allocator object */
46
SIXELSTATUS
47
sixel_allocator_new(
650✔
48
    sixel_allocator_t   /* out */ **ppallocator,  /* allocator object to be created */
49
    sixel_malloc_t      /* in */  fn_malloc,      /* custom malloc() function */
50
    sixel_calloc_t      /* in */  fn_calloc,      /* custom calloc() function */
51
    sixel_realloc_t     /* in */  fn_realloc,     /* custom realloc() function */
52
    sixel_free_t        /* in */  fn_free)        /* custom free() function */
53
{
54
    SIXELSTATUS status = SIXEL_FALSE;
650✔
55

56
    if (ppallocator == NULL) {
650!
57
        sixel_helper_set_additional_message(
×
58
            "sixel_allocator_new: given argument ppallocator is null.");
59
        status = SIXEL_BAD_ARGUMENT;
×
60
        goto end;
×
61
    }
62

63
    if (fn_malloc == NULL) {
650✔
64
        fn_malloc = malloc;
647✔
65
    }
217✔
66

67
    if (fn_calloc == NULL) {
650✔
68
        fn_calloc = calloc;
647✔
69
    }
217✔
70

71
    if (fn_realloc == NULL) {
650✔
72
        fn_realloc = realloc;
647✔
73
    }
217✔
74

75
    if (fn_free == NULL) {
650✔
76
        fn_free = free;
647✔
77
    }
217✔
78

79
    *ppallocator = fn_malloc(sizeof(sixel_allocator_t));
650✔
80
    if (*ppallocator == NULL) {
650!
81
        sixel_helper_set_additional_message(
×
82
            "sixel_allocator_new: fn_malloc() failed.");
83
        status = SIXEL_BAD_ALLOCATION;
×
84
        goto end;
×
85
    }
86

87
    (*ppallocator)->ref         = 1;
650✔
88
    (*ppallocator)->fn_malloc   = fn_malloc;
650✔
89
    (*ppallocator)->fn_calloc   = fn_calloc;
650✔
90
    (*ppallocator)->fn_realloc  = fn_realloc;
650✔
91
    (*ppallocator)->fn_free     = fn_free;
650✔
92

93
    status = SIXEL_OK;
650✔
94

95
end:
432✔
96
    return status;
650✔
97
}
98

99

100
/* destruct allocator object */
101
static void
102
sixel_allocator_destroy(
650✔
103
    sixel_allocator_t /* in */ *allocator)  /* allocator object to
104
                                               be destroyed */
105
{
106
    /* precondition */
107
    assert(allocator);
650!
108
    assert(allocator->fn_free);
650!
109

110
    allocator->fn_free(allocator);
650✔
111
}
650✔
112

113

114
/* increase reference count of allocator object (thread-safe) */
115
SIXELAPI void
116
sixel_allocator_ref(
3,901✔
117
    sixel_allocator_t /* in */ *allocator)  /* allocator object to be
118
                                               increment reference counter */
119
{
120
    unsigned int previous;
121

122
    /* precondition */
123
    assert(allocator);
3,901!
124

125
    /*
126
     * Increment the reference counter atomically so concurrent users can
127
     * retain the allocator without racing against a release in another
128
     * thread.
129
     */
130
    previous = sixel_atomic_fetch_add_u32(&allocator->ref, 1U);
3,901✔
131
    (void)previous;
1,395✔
132
}
3,901✔
133

134

135
/* decrease reference count of output context object (thread-safe) */
136
SIXELAPI void
137
sixel_allocator_unref(
4,551✔
138
    sixel_allocator_t /* in */ *allocator)  /* allocator object to be unreference */
139
{
140
    unsigned int previous;
141

142
    if (allocator) {
4,551!
143
        /*
144
         * Acquire the previous value atomically. The old count informs us
145
         * whether this thread dropped the last reference, which drives the
146
         * destruction path below.
147
         */
148
        previous = sixel_atomic_fetch_sub_u32(&allocator->ref, 1U);
4,551✔
149
        assert(previous > 0U);
4,551!
150
        if (previous == 1U) {
4,551✔
151
            sixel_allocator_destroy(allocator);
650✔
152
        }
218✔
153
    }
1,613✔
154
}
4,551✔
155

156

157
/* call custom malloc() */
158
SIXELAPI void *
159
sixel_allocator_malloc(
525,545✔
160
    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
161
    size_t              /* in */ n)           /* allocation size */
162
{
163
    /* precondition */
164
    assert(allocator);
525,545!
165
    assert(allocator->fn_malloc);
525,545!
166

167
    if (n == 0) {
525,545!
168
        sixel_helper_set_additional_message(
×
169
            "sixel_allocator_malloc: called with n == 0");
170
        return NULL;
×
171
    }
172

173
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
525,545!
174
        return NULL;
×
175
    }
176

177
    return allocator->fn_malloc(n);
525,545✔
178
}
176,301✔
179

180

181
/* call custom calloc() */
182
SIXELAPI void *
183
sixel_allocator_calloc(
1,864✔
184
    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
185
    size_t              /* in */ nelm,        /* number of elements */
186
    size_t              /* in */ elsize)      /* size of element */
187
{
188
    size_t n;
189

190
    /* precondition */
191
    assert(allocator);
1,864!
192
    assert(allocator->fn_calloc);
1,864!
193

194
    n = nelm * elsize;
1,864✔
195

196
    if (n == 0) {
1,864!
197
        sixel_helper_set_additional_message(
×
198
            "sixel_allocator_malloc: called with n == 0");
199
        return NULL;
×
200
    }
201

202
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
1,864!
203
        return NULL;
×
204
    }
205

206
    return allocator->fn_calloc(nelm, elsize);
1,864✔
207
}
654✔
208

209

210
/* call custom realloc() */
211
SIXELAPI void *
212
sixel_allocator_realloc(
960✔
213
    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
214
    void                /* in */ *p,          /* existing buffer to be re-allocated */
215
    size_t              /* in */ n)           /* re-allocation size */
216
{
217
    /* precondition */
218
    assert(allocator);
960!
219
    assert(allocator->fn_realloc);
960!
220

221
    if (n == 0) {
960!
222
        sixel_helper_set_additional_message(
×
223
            "sixel_allocator_malloc: called with n == 0");
224
        return NULL;
×
225
    }
226

227
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
960!
228
        return NULL;
×
229
    }
230

231
    return allocator->fn_realloc(p, n);
960✔
232
}
260✔
233

234

235
/* call custom free() */
236
SIXELAPI void
237
sixel_allocator_free(
536,151✔
238
    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
239
    void                /* in */ *p)          /* existing buffer to be freed */
240
{
241
    /* precondition */
242
    assert(allocator);
536,151!
243

244
    allocator->fn_free(p);
536,151✔
245
}
536,151✔
246

247

248
#if HAVE_TESTS
249
volatile int sixel_debug_malloc_counter;
250

251
void *
252
sixel_bad_malloc(size_t size)
×
253
{
254
    return sixel_debug_malloc_counter-- == 0 ? NULL: malloc(size);
×
255
}
256

257

258
void *
259
sixel_bad_calloc(size_t count, size_t size)
×
260
{
261
    (void) count;
262
    (void) size;
263

264
    return NULL;
×
265
}
266

267

268
void *
269
sixel_bad_realloc(void *ptr, size_t size)
×
270
{
271
    (void) ptr;
272
    (void) size;
273

274
    return NULL;
×
275
}
276
#endif  /* HAVE_TESTS */
277

278
#if 0
279
int
280
rpl_posix_memalign(void **memptr, size_t alignment, size_t size)
281
{
282
#if HAVE_POSIX_MEMALIGN
283
    return posix_memalign(memptr, alignment, size);
284
#elif HAVE_ALIGNED_ALLOC
285
    *memptr = aligned_alloc(alignment, size);
286
    return *memptr ? 0: ENOMEM;
287
#elif HAVE_MEMALIGN
288
    *memptr = memalign(alignment, size);
289
    return *memptr ? 0: ENOMEM;
290
#elif HAVE__ALIGNED_MALLOC
291
    return _aligned_malloc(size, alignment);
292
#else
293
# error
294
#endif /* _MSC_VER */
295
}
296
#endif
297

298

299
#if HAVE_TESTS
300
static int
301
test1(void)
×
302
{
303
    int nret = EXIT_FAILURE;
×
304
    SIXELSTATUS status;
305
    sixel_allocator_t *allocator = NULL;
×
306

307
    status = sixel_allocator_new(NULL, malloc, calloc, realloc, free);
×
308
    if (status != SIXEL_BAD_ARGUMENT) {
×
309
        goto error;
×
310
    }
311

312
    status = sixel_allocator_new(&allocator, NULL, calloc, realloc, free);
×
313
    if (SIXEL_FAILED(status)) {
×
314
        goto error;
×
315
    }
316

317
    status = sixel_allocator_new(&allocator, malloc, NULL, realloc, free);
×
318
    if (SIXEL_FAILED(status)) {
×
319
        goto error;
×
320
    }
321

322
    status = sixel_allocator_new(&allocator, malloc, calloc, NULL, free);
×
323
    if (SIXEL_FAILED(status)) {
×
324
        goto error;
×
325
    }
326

327
    status = sixel_allocator_new(&allocator, malloc, calloc, realloc, NULL);
×
328
    if (SIXEL_FAILED(status)) {
×
329
        goto error;
×
330
    }
331

332
    nret = EXIT_SUCCESS;
×
333

334
error:
335
    return nret;
×
336
}
337

338

339
static int
340
test2(void)
×
341
{
342
    int nret = EXIT_FAILURE;
×
343
    SIXELSTATUS status;
344
    sixel_allocator_t *allocator = NULL;
×
345

346
    sixel_debug_malloc_counter = 1;
×
347

348
    status = sixel_allocator_new(&allocator, sixel_bad_malloc, calloc, realloc, free);
×
349
    if (status == SIXEL_BAD_ALLOCATION) {
×
350
        goto error;
×
351
    }
352

353
    nret = EXIT_SUCCESS;
×
354

355
error:
356
    return nret;
×
357
}
358

359

360
SIXELAPI int
361
sixel_allocator_tests_main(void)
×
362
{
363
    int nret = EXIT_FAILURE;
×
364
    size_t i;
365
    typedef int (* testcase)(void);
366

367
    static testcase const testcases[] = {
368
        test1,
369
        test2
370
    };
371

372
    for (i = 0; i < sizeof(testcases) / sizeof(testcase); ++i) {
×
373
        nret = testcases[i]();
×
374
        if (nret != EXIT_SUCCESS) {
×
375
            goto error;
×
376
        }
377
    }
378

379
    nret = EXIT_SUCCESS;
×
380

381
error:
382
    return nret;
×
383
}
384
#endif  /* HAVE_TESTS */
385

386
/* emacs Local Variables:      */
387
/* emacs mode: c               */
388
/* emacs tab-width: 4          */
389
/* emacs indent-tabs-mode: nil */
390
/* emacs c-basic-offset: 4     */
391
/* emacs End:                  */
392
/* vim: set expandtab ts=4 sts=4 sw=4 : */
393
/* EOF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc