xref: /freebsd/contrib/pam-krb5/portable/reallocarray.c (revision bf6873c5786e333d679a7838d28812febf479a8a)
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