1 /* xmalloc.c -- malloc with out of memory checking 2 3 Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 4 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software Foundation, 18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 19 #include <sys/cdefs.h> 20 __RCSID("$NetBSD: xmalloc.c,v 1.2 2016/05/17 14:00:09 christos Exp $"); 21 22 23 #ifdef HAVE_CONFIG_H 24 # include <config.h> 25 #endif 26 27 #include "xalloc.h" 28 29 #include <stdlib.h> 30 #include <string.h> 31 32 #ifndef SIZE_MAX 33 # define SIZE_MAX ((size_t) -1) 34 #endif 35 36 /* 1 if calloc is known to be compatible with GNU calloc. This 37 matters if we are not also using the calloc module, which defines 38 HAVE_CALLOC and supports the GNU API even on non-GNU platforms. */ 39 #if defined HAVE_CALLOC || defined __GLIBC__ 40 enum { HAVE_GNU_CALLOC = 1 }; 41 #else 42 enum { HAVE_GNU_CALLOC = 0 }; 43 #endif 44 45 /* Allocate an array of N objects, each with S bytes of memory, 46 dynamically, with error checking. S must be nonzero. */ 47 48 static inline void * 49 xnmalloc_inline (size_t n, size_t s) 50 { 51 void *p; 52 if (xalloc_oversized (n, s) || (! (p = malloc (n * s)) && n != 0)) 53 xalloc_die (); 54 return p; 55 } 56 57 void * 58 xnmalloc (size_t n, size_t s) 59 { 60 return xnmalloc_inline (n, s); 61 } 62 63 /* Allocate N bytes of memory dynamically, with error checking. */ 64 65 void * 66 xmalloc (size_t n) 67 { 68 return xnmalloc_inline (n, 1); 69 } 70 71 /* Change the size of an allocated block of memory P to an array of N 72 objects each of S bytes, with error checking. S must be nonzero. */ 73 74 static inline void * 75 xnrealloc_inline (void *p, size_t n, size_t s) 76 { 77 if (xalloc_oversized (n, s) || (! (p = realloc (p, n * s)) && n != 0)) 78 xalloc_die (); 79 return p; 80 } 81 82 void * 83 xnrealloc (void *p, size_t n, size_t s) 84 { 85 return xnrealloc_inline (p, n, s); 86 } 87 88 /* Change the size of an allocated block of memory P to N bytes, 89 with error checking. */ 90 91 void * 92 xrealloc (void *p, size_t n) 93 { 94 return xnrealloc_inline (p, n, 1); 95 } 96 97 98 /* If P is null, allocate a block of at least *PN such objects; 99 otherwise, reallocate P so that it contains more than *PN objects 100 each of S bytes. *PN must be nonzero unless P is null, and S must 101 be nonzero. Set *PN to the new number of objects, and return the 102 pointer to the new block. *PN is never set to zero, and the 103 returned pointer is never null. 104 105 Repeated reallocations are guaranteed to make progress, either by 106 allocating an initial block with a nonzero size, or by allocating a 107 larger block. 108 109 In the following implementation, nonzero sizes are doubled so that 110 repeated reallocations have O(N log N) overall cost rather than 111 O(N**2) cost, but the specification for this function does not 112 guarantee that sizes are doubled. 113 114 Here is an example of use: 115 116 int *p = NULL; 117 size_t used = 0; 118 size_t allocated = 0; 119 120 void 121 append_int (int value) 122 { 123 if (used == allocated) 124 p = x2nrealloc (p, &allocated, sizeof *p); 125 p[used++] = value; 126 } 127 128 This causes x2nrealloc to allocate a block of some nonzero size the 129 first time it is called. 130 131 To have finer-grained control over the initial size, set *PN to a 132 nonzero value before calling this function with P == NULL. For 133 example: 134 135 int *p = NULL; 136 size_t used = 0; 137 size_t allocated = 0; 138 size_t allocated1 = 1000; 139 140 void 141 append_int (int value) 142 { 143 if (used == allocated) 144 { 145 p = x2nrealloc (p, &allocated1, sizeof *p); 146 allocated = allocated1; 147 } 148 p[used++] = value; 149 } 150 151 */ 152 153 static inline void * 154 x2nrealloc_inline (void *p, size_t *pn, size_t s) 155 { 156 size_t n = *pn; 157 158 if (! p) 159 { 160 if (! n) 161 { 162 /* The approximate size to use for initial small allocation 163 requests, when the invoking code specifies an old size of 164 zero. 64 bytes is the largest "small" request for the 165 GNU C library malloc. */ 166 enum { DEFAULT_MXFAST = 64 }; 167 168 n = DEFAULT_MXFAST / s; 169 n += !n; 170 } 171 } 172 else 173 { 174 if (SIZE_MAX / 2 / s < n) 175 xalloc_die (); 176 n *= 2; 177 } 178 179 *pn = n; 180 return xrealloc (p, n * s); 181 } 182 183 void * 184 x2nrealloc (void *p, size_t *pn, size_t s) 185 { 186 return x2nrealloc_inline (p, pn, s); 187 } 188 189 /* If P is null, allocate a block of at least *PN bytes; otherwise, 190 reallocate P so that it contains more than *PN bytes. *PN must be 191 nonzero unless P is null. Set *PN to the new block's size, and 192 return the pointer to the new block. *PN is never set to zero, and 193 the returned pointer is never null. */ 194 195 void * 196 x2realloc (void *p, size_t *pn) 197 { 198 return x2nrealloc_inline (p, pn, 1); 199 } 200 201 /* Allocate S bytes of zeroed memory dynamically, with error checking. 202 There's no need for xnzalloc (N, S), since it would be equivalent 203 to xcalloc (N, S). */ 204 205 void * 206 xzalloc (size_t s) 207 { 208 return memset (xmalloc (s), 0, s); 209 } 210 211 /* Allocate zeroed memory for N elements of S bytes, with error 212 checking. S must be nonzero. */ 213 214 void * 215 xcalloc (size_t n, size_t s) 216 { 217 void *p; 218 /* Test for overflow, since some calloc implementations don't have 219 proper overflow checks. But omit overflow and size-zero tests if 220 HAVE_GNU_CALLOC, since GNU calloc catches overflow and never 221 returns NULL if successful. */ 222 if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s)) 223 || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) 224 xalloc_die (); 225 return p; 226 } 227 228 /* Clone an object P of size S, with error checking. There's no need 229 for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any 230 need for an arithmetic overflow check. */ 231 232 void * 233 xmemdup (void const *p, size_t s) 234 { 235 return memcpy (xmalloc (s), p, s); 236 } 237 238 /* Clone STRING. */ 239 240 char * 241 xstrdup (char const *string) 242 { 243 return xmemdup (string, strlen (string) + 1); 244 } 245