1*bf6873c5SCy Schubert /*
2*bf6873c5SCy Schubert * Replacement for a missing reallocarray.
3*bf6873c5SCy Schubert *
4*bf6873c5SCy Schubert * Provides the same functionality as the OpenBSD library function
5*bf6873c5SCy Schubert * reallocarray for those systems that don't have it. This function is the
6*bf6873c5SCy Schubert * same as realloc, but takes the size arguments in the same form as calloc
7*bf6873c5SCy Schubert * and checks for overflow so that the caller doesn't need to.
8*bf6873c5SCy Schubert *
9*bf6873c5SCy Schubert * The canonical version of this file is maintained in the rra-c-util package,
10*bf6873c5SCy Schubert * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
11*bf6873c5SCy Schubert *
12*bf6873c5SCy Schubert * Written by Russ Allbery <eagle@eyrie.org>
13*bf6873c5SCy Schubert * Copyright 2017 Russ Allbery <eagle@eyrie.org>
14*bf6873c5SCy Schubert * Copyright 2014
15*bf6873c5SCy Schubert * The Board of Trustees of the Leland Stanford Junior University
16*bf6873c5SCy Schubert *
17*bf6873c5SCy Schubert * Copying and distribution of this file, with or without modification, are
18*bf6873c5SCy Schubert * permitted in any medium without royalty provided the copyright notice and
19*bf6873c5SCy Schubert * this notice are preserved. This file is offered as-is, without any
20*bf6873c5SCy Schubert * warranty.
21*bf6873c5SCy Schubert *
22*bf6873c5SCy Schubert * SPDX-License-Identifier: FSFAP
23*bf6873c5SCy Schubert */
24*bf6873c5SCy Schubert
25*bf6873c5SCy Schubert #include <config.h>
26*bf6873c5SCy Schubert #include <portable/system.h>
27*bf6873c5SCy Schubert
28*bf6873c5SCy Schubert #include <errno.h>
29*bf6873c5SCy Schubert
30*bf6873c5SCy Schubert /*
31*bf6873c5SCy Schubert * If we're running the test suite, rename reallocarray to avoid conflicts
32*bf6873c5SCy Schubert * with the system version. #undef it first because some systems may define
33*bf6873c5SCy Schubert * it to another name.
34*bf6873c5SCy Schubert */
35*bf6873c5SCy Schubert #if TESTING
36*bf6873c5SCy Schubert # undef reallocarray
37*bf6873c5SCy Schubert # define reallocarray test_reallocarray
38*bf6873c5SCy Schubert void *test_reallocarray(void *, size_t, size_t);
39*bf6873c5SCy Schubert #endif
40*bf6873c5SCy Schubert
41*bf6873c5SCy Schubert /*
42*bf6873c5SCy Schubert * nmemb * size cannot overflow if both are smaller than sqrt(SIZE_MAX). We
43*bf6873c5SCy Schubert * can calculate that value statically by using 2^(sizeof(size_t) * 8) as the
44*bf6873c5SCy Schubert * value of SIZE_MAX and then taking the square root, which gives
45*bf6873c5SCy Schubert * 2^(sizeof(size_t) * 4). Compute the exponentiation with shift.
46*bf6873c5SCy Schubert */
47*bf6873c5SCy Schubert #define CHECK_THRESHOLD (1UL << (sizeof(size_t) * 4))
48*bf6873c5SCy Schubert
49*bf6873c5SCy Schubert void *
reallocarray(void * ptr,size_t nmemb,size_t size)50*bf6873c5SCy Schubert reallocarray(void *ptr, size_t nmemb, size_t size)
51*bf6873c5SCy Schubert {
52*bf6873c5SCy Schubert if (nmemb >= CHECK_THRESHOLD || size >= CHECK_THRESHOLD)
53*bf6873c5SCy Schubert if (nmemb > 0 && SIZE_MAX / nmemb <= size) {
54*bf6873c5SCy Schubert errno = ENOMEM;
55*bf6873c5SCy Schubert return NULL;
56*bf6873c5SCy Schubert }
57*bf6873c5SCy Schubert
58*bf6873c5SCy Schubert /* Avoid a zero-size allocation. */
59*bf6873c5SCy Schubert if (nmemb == 0 || size == 0) {
60*bf6873c5SCy Schubert nmemb = 1;
61*bf6873c5SCy Schubert size = 1;
62*bf6873c5SCy Schubert }
63*bf6873c5SCy Schubert return realloc(ptr, nmemb * size);
64*bf6873c5SCy Schubert }
65