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

saitoha / libsixel / 20466639304

23 Dec 2025 04:53PM UTC coverage: 51.46% (-6.3%) from 57.773%
20466639304

push

github

saitoha
build: fix windows find path in images meson build

14511 of 44933 branches covered (32.29%)

21089 of 40981 relevant lines covered (51.46%)

3915123.44 hits per line

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

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

25
#include "config.h"
26

27
/* STDC_HEADERS */
28
#include <stdlib.h>
29

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

43
#include "allocator.h"
44
#include "malloc_stub.h"
45
#include "sixel_atomic.h"
46

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

58
    if (ppallocator == NULL) {
1,109!
59
        sixel_helper_set_additional_message(
×
60
            "sixel_allocator_new: given argument ppallocator is null.");
61
        status = SIXEL_BAD_ARGUMENT;
×
62
        goto end;
×
63
    }
64

65
    if (fn_malloc == NULL) {
1,109✔
66
        fn_malloc = malloc;
940✔
67
    }
68

69
    if (fn_calloc == NULL) {
1,109✔
70
        fn_calloc = calloc;
940✔
71
    }
72

73
    if (fn_realloc == NULL) {
1,109✔
74
        fn_realloc = realloc;
940✔
75
    }
76

77
    if (fn_free == NULL) {
1,109✔
78
        fn_free = free;
940✔
79
    }
80

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

89
    (*ppallocator)->ref         = 1;
1,109✔
90
    (*ppallocator)->fn_malloc   = fn_malloc;
1,109✔
91
    (*ppallocator)->fn_calloc   = fn_calloc;
1,109✔
92
    (*ppallocator)->fn_realloc  = fn_realloc;
1,109✔
93
    (*ppallocator)->fn_free     = fn_free;
1,109✔
94

95
    status = SIXEL_OK;
1,109✔
96

97
end:
1,109✔
98
    return status;
1,109✔
99
}
100

101

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

112
    allocator->fn_free(allocator);
480✔
113
}
480✔
114

115

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

124
    /* precondition */
125
    assert(allocator);
6,547!
126

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

136

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

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

158

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

169
    if (n == 0) {
2,568,553!
170
        sixel_helper_set_additional_message(
×
171
            "sixel_allocator_malloc: called with n == 0");
172
        return NULL;
×
173
    }
174

175
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
2,568,553!
176
        return NULL;
177
    }
178

179
    return allocator->fn_malloc(n);
2,568,553✔
180
}
181

182

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

192
    /* precondition */
193
    assert(allocator);
2,888!
194
    assert(allocator->fn_calloc);
2,888!
195

196
    n = nelm * elsize;
2,888✔
197

198
    if (n == 0) {
2,888!
199
        sixel_helper_set_additional_message(
×
200
            "sixel_allocator_malloc: called with n == 0");
201
        return NULL;
×
202
    }
203

204
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
2,888!
205
        return NULL;
206
    }
207

208
    return allocator->fn_calloc(nelm, elsize);
2,888✔
209
}
210

211

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

223
    if (n == 0) {
2,074!
224
        sixel_helper_set_additional_message(
×
225
            "sixel_allocator_malloc: called with n == 0");
226
        return NULL;
×
227
    }
228

229
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
2,074!
230
        return NULL;
231
    }
232

233
    return allocator->fn_realloc(p, n);
2,074✔
234
}
235

236

237
/* call custom free() */
238
SIXELAPI void
239
sixel_allocator_free(
2,579,044✔
240
    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
241
    void                /* in */ *p)          /* existing buffer to be freed */
242
{
243
    /* precondition */
244
    assert(allocator);
2,579,044!
245

246
    allocator->fn_free(p);
2,579,044✔
247
}
2,579,044✔
248

249

250
#if HAVE_TESTS
251
volatile int sixel_debug_malloc_counter;
252

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

259

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

266
    return NULL;
×
267
}
268

269

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

276
    return NULL;
×
277
}
278
#endif  /* HAVE_TESTS */
279

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

300

301
/*
302
 * Confirm that allocator construction validates callback arguments and
303
 * reports missing functions as bad arguments.
304
 */
305
#if HAVE_TESTS
306
static int
307
allocator_test_rejects_null_callbacks(void)
×
308
{
309
    int nret = EXIT_FAILURE;
×
310
    SIXELSTATUS status;
×
311
    sixel_allocator_t *allocator = NULL;
×
312

313
    status = sixel_allocator_new(NULL, malloc, calloc, realloc, free);
×
314
    if (status != SIXEL_BAD_ARGUMENT) {
×
315
        goto error;
316
    }
317

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

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

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

333
    status = sixel_allocator_new(&allocator, malloc, calloc, realloc, NULL);
×
334
    if (SIXEL_FAILED(status)) {
×
335
        goto error;
×
336
    }
337

338
    nret = EXIT_SUCCESS;
339

340
error:
×
341
    return nret;
×
342
}
343

344

345
/*
346
 * Ensure debug allocation counters surface allocation failures from custom
347
 * callbacks.
348
 */
349
static int
350
allocator_test_reports_debug_allocation(void)
×
351
{
352
    int nret = EXIT_FAILURE;
×
353
    SIXELSTATUS status;
×
354
    sixel_allocator_t *allocator = NULL;
×
355

356
    sixel_debug_malloc_counter = 1;
×
357

358
    status = sixel_allocator_new(
×
359
        &allocator,
360
        sixel_bad_malloc,
361
        calloc,
362
        realloc,
363
        free);
364
    if (status == SIXEL_BAD_ALLOCATION) {
×
365
        goto error;
×
366
    }
367

368
    nret = EXIT_SUCCESS;
369

370
error:
×
371
    return nret;
×
372
}
373

374

375
SIXELAPI int
376
sixel_allocator_tests_main(void)
×
377
{
378
    int nret = EXIT_FAILURE;
×
379
    size_t i;
×
380
    typedef int (* testcase)(void);
×
381

382
    static testcase const testcases[] = {
×
383
        allocator_test_rejects_null_callbacks,
384
        allocator_test_reports_debug_allocation
385
    };
386

387
    for (i = 0; i < sizeof(testcases) / sizeof(testcase); ++i) {
×
388
        nret = testcases[i]();
×
389
        if (nret != EXIT_SUCCESS) {
×
390
            goto error;
×
391
        }
392
    }
393

394
    nret = EXIT_SUCCESS;
395

396
error:
×
397
    return nret;
×
398
}
399
#endif  /* HAVE_TESTS */
400

401
/* emacs Local Variables:      */
402
/* emacs mode: c               */
403
/* emacs tab-width: 4          */
404
/* emacs indent-tabs-mode: nil */
405
/* emacs c-basic-offset: 4     */
406
/* emacs End:                  */
407
/* vim: set expandtab ts=4 sts=4 sw=4 : */
408
/* 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