maint: update copyright
[gnulib.git] / lib / safe-alloc.c
1 /* safe-alloc.c: safer memory allocation
2
3    Copyright (C) 2009-2014 Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify it
6    under the terms of the GNU General Public License as published by the
7    Free Software Foundation; either version 3 of the License, or any
8    later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 /* Written by Daniel Berrange <berrange@redhat.com>, 2008 */
19
20 #include <config.h>
21
22 /* Specification.  */
23 #include "safe-alloc.h"
24
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <errno.h>
28
29
30 /* Return 1 if an array of N objects, each of size S, cannot exist due
31    to size arithmetic overflow.  S must be positive and N must be
32    nonnegative.  This is a macro, not a function, so that it
33    works correctly even when SIZE_MAX < N.
34
35    By gnulib convention, SIZE_MAX represents overflow in size
36    calculations, so the conservative dividend to use here is
37    SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
38    However, malloc (SIZE_MAX) fails on all known hosts where
39    sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
40    exactly-SIZE_MAX allocations on such hosts; this avoids a test and
41    branch when S is known to be 1.
42
43    This is the same as xalloc_oversized from xalloc.h
44 */
45 #define safe_alloc_oversized(n, s)                                      \
46   ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
47
48
49 /**
50  * safe_alloc_alloc_n:
51  * @ptrptr: pointer to pointer for address of allocated memory
52  * @size: number of bytes to allocate
53  * @count: number of elements to allocate
54  *
55  * Allocate an array of memory 'count' elements long,
56  * each with 'size' bytes. Return the address of the
57  * allocated memory in 'ptrptr'.  The newly allocated
58  * memory is filled with zeros.
59  *
60  * Return -1 on failure to allocate, zero on success
61  */
62 int
63 safe_alloc_alloc_n (void *ptrptr, size_t size, size_t count, int zeroed)
64 {
65   if (size == 0 || count == 0)
66     {
67       *(void **) ptrptr = NULL;
68       return 0;
69     }
70
71   if (safe_alloc_oversized (count, size))
72     {
73       errno = ENOMEM;
74       return -1;
75     }
76
77   if (zeroed)
78     *(void **) ptrptr = calloc (count, size);
79   else
80     *(void **) ptrptr = malloc (count * size);
81
82   if (*(void **) ptrptr == NULL)
83     return -1;
84   return 0;
85 }
86
87 /**
88  * safe_alloc_realloc_n:
89  * @ptrptr: pointer to pointer for address of allocated memory
90  * @size: number of bytes to allocate
91  * @count: number of elements in array
92  *
93  * Resize the block of memory in 'ptrptr' to be an array of
94  * 'count' elements, each 'size' bytes in length. Update 'ptrptr'
95  * with the address of the newly allocated memory. On failure,
96  * 'ptrptr' is not changed and still points to the original memory
97  * block. The newly allocated memory is filled with zeros.
98  *
99  * Return -1 on failure to allocate, zero on success
100  */
101 int
102 safe_alloc_realloc_n (void *ptrptr, size_t size, size_t count)
103 {
104   void *tmp;
105   if (size == 0 || count == 0)
106     {
107       free (*(void **) ptrptr);
108       *(void **) ptrptr = NULL;
109       return 0;
110     }
111   if (safe_alloc_oversized (count, size))
112     {
113       errno = ENOMEM;
114       return -1;
115     }
116   tmp = realloc (*(void **) ptrptr, size * count);
117   if (!tmp)
118     return -1;
119   *(void **) ptrptr = tmp;
120   return 0;
121 }