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

saitoha / libsixel / 19934796867

04 Dec 2025 03:42PM UTC coverage: 43.522% (+2.3%) from 41.258%
19934796867

push

github

saitoha
python: update shared api.py

10714 of 38654 branches covered (27.72%)

14673 of 33714 relevant lines covered (43.52%)

2910517.57 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(
715✔
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;
715✔
57

58
    if (ppallocator == NULL) {
715!
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) {
715✔
66
        fn_malloc = malloc;
648✔
67
    }
68

69
    if (fn_calloc == NULL) {
715✔
70
        fn_calloc = calloc;
648✔
71
    }
72

73
    if (fn_realloc == NULL) {
715✔
74
        fn_realloc = realloc;
648✔
75
    }
76

77
    if (fn_free == NULL) {
715✔
78
        fn_free = free;
648✔
79
    }
80

81
    *ppallocator = fn_malloc(sizeof(sixel_allocator_t));
715✔
82
    if (*ppallocator == NULL) {
715!
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;
715✔
90
    (*ppallocator)->fn_malloc   = fn_malloc;
715✔
91
    (*ppallocator)->fn_calloc   = fn_calloc;
715✔
92
    (*ppallocator)->fn_realloc  = fn_realloc;
715✔
93
    (*ppallocator)->fn_free     = fn_free;
715✔
94

95
    status = SIXEL_OK;
715✔
96

97
end:
715✔
98
    return status;
715✔
99
}
100

101

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

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

115

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

124
    /* precondition */
125
    assert(allocator);
4,199!
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);
4,199✔
133
    (void)previous;
4,199✔
134
}
4,199✔
135

136

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

144
    if (allocator) {
4,911!
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);
4,911!
151
        assert(previous > 0U);
4,911!
152
        if (previous == 1U) {
4,911✔
153
            sixel_allocator_destroy(allocator);
712✔
154
        }
155
    }
156
}
4,911✔
157

158

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

169
    if (n == 0) {
459,857!
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) {
459,857!
176
        return NULL;
177
    }
178

179
    return allocator->fn_malloc(n);
459,857✔
180
}
181

182

183
/* call custom calloc() */
184
SIXELAPI void *
185
sixel_allocator_calloc(
1,632✔
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;
1,632✔
191

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

196
    n = nelm * elsize;
1,632✔
197

198
    if (n == 0) {
1,632!
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) {
1,632!
205
        return NULL;
206
    }
207

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

211

212
/* call custom realloc() */
213
SIXELAPI void *
214
sixel_allocator_realloc(
1,244✔
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);
1,244!
221
    assert(allocator->fn_realloc);
1,244!
222

223
    if (n == 0) {
1,244!
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) {
1,244!
230
        return NULL;
231
    }
232

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

236

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

246
    allocator->fn_free(p);
470,784✔
247
}
470,784✔
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
#if HAVE_TESTS
302
static int
303
test1(void)
×
304
{
305
    int nret = EXIT_FAILURE;
×
306
    SIXELSTATUS status;
×
307
    sixel_allocator_t *allocator = NULL;
×
308

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

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

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

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

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

334
    nret = EXIT_SUCCESS;
335

336
error:
×
337
    return nret;
×
338
}
339

340

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

348
    sixel_debug_malloc_counter = 1;
×
349

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

355
    nret = EXIT_SUCCESS;
356

357
error:
×
358
    return nret;
×
359
}
360

361

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

369
    static testcase const testcases[] = {
×
370
        test1,
371
        test2
372
    };
373

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

381
    nret = EXIT_SUCCESS;
382

383
error:
×
384
    return nret;
×
385
}
386
#endif  /* HAVE_TESTS */
387

388
/* emacs Local Variables:      */
389
/* emacs mode: c               */
390
/* emacs tab-width: 4          */
391
/* emacs indent-tabs-mode: nil */
392
/* emacs c-basic-offset: 4     */
393
/* emacs End:                  */
394
/* vim: set expandtab ts=4 sts=4 sw=4 : */
395
/* 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