Coverage Report

Created: 2023-09-23 17:42

/libfido2/openbsd-compat/recallocarray.c
Line
Count
Source (jump to first uncovered line)
1
/*      $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $  */
2
/*
3
 * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
19
20
#include "openbsd-compat.h"
21
22
#if !defined(HAVE_RECALLOCARRAY)
23
24
#include <errno.h>
25
#include <stdlib.h>
26
#include <stdint.h>
27
#include <string.h>
28
#ifdef HAVE_UNISTD_H
29
#include <unistd.h>
30
#endif
31
32
/*
33
 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
34
 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
35
 */
36
765k
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
37
38
void *
39
recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
40
169k
{
41
169k
        size_t oldsize, newsize;
42
169k
        void *newptr;
43
44
169k
        if (ptr == NULL)
45
41.6k
                return calloc(newnmemb, size);
46
47
127k
        if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
48
127k
            newnmemb > 0 && SIZE_MAX / newnmemb < size) {
49
0
                errno = ENOMEM;
50
0
                return NULL;
51
0
        }
52
127k
        newsize = newnmemb * size;
53
54
127k
        if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
55
127k
            oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
56
0
                errno = EINVAL;
57
0
                return NULL;
58
0
        }
59
127k
        oldsize = oldnmemb * size;
60
        
61
        /*
62
         * Don't bother too much if we're shrinking just a bit,
63
         * we do not shrink for series of small steps, oh well.
64
         */
65
127k
        if (newsize <= oldsize) {
66
2
                size_t d = oldsize - newsize;
67
68
2
                if (d < oldsize / 2 && d < (size_t)getpagesize()) {
69
2
                        memset((char *)ptr + newsize, 0, d);
70
2
                        return ptr;
71
2
                }
72
2
        }
73
74
127k
        newptr = malloc(newsize);
75
127k
        if (newptr == NULL)
76
343
                return NULL;
77
78
127k
        if (newsize > oldsize) {
79
127k
                memcpy(newptr, ptr, oldsize);
80
127k
                memset((char *)newptr + oldsize, 0, newsize - oldsize);
81
127k
        } else
82
0
                memcpy(newptr, ptr, newsize);
83
84
127k
        explicit_bzero(ptr, oldsize);
85
127k
        free(ptr);
86
87
127k
        return newptr;
88
127k
}
89
/* DEF_WEAK(recallocarray); */
90
91
#endif /* !defined(HAVE_RECALLOCARRAY) */