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

saitoha / libsixel / 20578371047

29 Dec 2025 05:06PM UTC coverage: 51.955% (-5.4%) from 57.322%
20578371047

push

github

saitoha
Revert "Merge branch 'refactor/pixelformat' into develop"

This reverts commit 4a6153922, reversing
changes made to 6f3ef3068.

14746 of 45077 branches covered (32.71%)

147 of 262 new or added lines in 15 files covered. (56.11%)

1406 existing lines in 46 files now uncovered.

21419 of 41226 relevant lines covered (51.96%)

3895522.67 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
#if defined(HAVE_CONFIG_H)
26
#include "config.h"
27
#endif
28

29
/* STDC_HEADERS */
30
#include <stdlib.h>
31

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

45
#include "allocator.h"
46
#include "malloc_stub.h"
47
#include "sixel_atomic.h"
48

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

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

67
    if (fn_malloc == NULL) {
1,138✔
68
        fn_malloc = malloc;
969✔
69
    }
70

71
    if (fn_calloc == NULL) {
1,138✔
72
        fn_calloc = calloc;
969✔
73
    }
74

75
    if (fn_realloc == NULL) {
1,138✔
76
        fn_realloc = realloc;
969✔
77
    }
78

79
    if (fn_free == NULL) {
1,138✔
80
        fn_free = free;
969✔
81
    }
82

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

91
    (*ppallocator)->ref         = 1;
1,138✔
92
    (*ppallocator)->fn_malloc   = fn_malloc;
1,138✔
93
    (*ppallocator)->fn_calloc   = fn_calloc;
1,138✔
94
    (*ppallocator)->fn_realloc  = fn_realloc;
1,138✔
95
    (*ppallocator)->fn_free     = fn_free;
1,138✔
96

97
    status = SIXEL_OK;
1,138✔
98

99
end:
1,138✔
100
    return status;
1,138✔
101
}
102

103

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

114
    allocator->fn_free(allocator);
509✔
115
}
509✔
116

117

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

126
    /* precondition */
127
    assert(allocator);
6,556!
128

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

138

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

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

160

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

171
    if (n == 0) {
2,569,803!
172
        sixel_helper_set_additional_message(
×
173
            "sixel_allocator_malloc: called with n == 0");
174
        return NULL;
×
175
    }
176

177
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
2,569,803!
178
        return NULL;
179
    }
180

181
    return allocator->fn_malloc(n);
2,569,803✔
182
}
183

184

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

194
    /* precondition */
195
    assert(allocator);
2,889!
196
    assert(allocator->fn_calloc);
2,889!
197

198
    n = nelm * elsize;
2,889✔
199

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

206
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
2,889!
207
        return NULL;
208
    }
209

210
    return allocator->fn_calloc(nelm, elsize);
2,889✔
211
}
212

213

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

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

231
    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
2,086!
232
        return NULL;
233
    }
234

235
    return allocator->fn_realloc(p, n);
2,086✔
236
}
237

238

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

248
    allocator->fn_free(p);
2,580,311✔
249
}
2,580,311✔
250

251

252
#if HAVE_TESTS
253
volatile int sixel_debug_malloc_counter;
254

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

261

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

268
    return NULL;
×
269
}
270

271

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

278
    return NULL;
×
279
}
280
#endif  /* HAVE_TESTS */
281

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

302

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

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

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

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

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

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

340
    nret = EXIT_SUCCESS;
341

UNCOV
342
error:
×
343
    return nret;
×
344
}
345

346

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

358
    sixel_debug_malloc_counter = 1;
×
359

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

370
    nret = EXIT_SUCCESS;
371

UNCOV
372
error:
×
373
    return nret;
×
374
}
375

376

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

UNCOV
384
    static testcase const testcases[] = {
×
385
        allocator_test_rejects_null_callbacks,
386
        allocator_test_reports_debug_allocation
387
    };
388

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

396
    nret = EXIT_SUCCESS;
397

UNCOV
398
error:
×
399
    return nret;
×
400
}
401
#endif  /* HAVE_TESTS */
402

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