Branch data Line data Source code
1 : : /* xsize.h -- Checked size_t computations.
2 : :
3 : : Copyright (C) 2003, 2008-2012 Free Software Foundation, Inc.
4 : :
5 : : This program is free software; you can redistribute it and/or modify
6 : : it under the terms of the GNU General Public License as published by
7 : : the Free Software Foundation; either version 3, or (at your option)
8 : : any 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 : : #ifndef _XSIZE_H
19 : : #define _XSIZE_H
20 : :
21 : : /* Get size_t. */
22 : : #include <stddef.h>
23 : :
24 : : /* Get SIZE_MAX. */
25 : : #include <limits.h>
26 : : #if HAVE_STDINT_H
27 : : # include <stdint.h>
28 : : #endif
29 : :
30 : : /* The size of memory objects is often computed through expressions of
31 : : type size_t. Example:
32 : : void* p = malloc (header_size + n * element_size).
33 : : These computations can lead to overflow. When this happens, malloc()
34 : : returns a piece of memory that is way too small, and the program then
35 : : crashes while attempting to fill the memory.
36 : : To avoid this, the functions and macros in this file check for overflow.
37 : : The convention is that SIZE_MAX represents overflow.
38 : : malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
39 : : implementation that uses mmap --, it's recommended to use size_overflow_p()
40 : : or size_in_bounds_p() before invoking malloc().
41 : : The example thus becomes:
42 : : size_t size = xsum (header_size, xtimes (n, element_size));
43 : : void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
44 : : */
45 : :
46 : : /* Convert an arbitrary value >= 0 to type size_t. */
47 : : #define xcast_size_t(N) \
48 : : ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
49 : :
50 : : /* Sum of two sizes, with overflow check. */
51 : : static inline size_t
52 : : #if __GNUC__ >= 3
53 : : __attribute__ ((__pure__))
54 : : #endif
55 : 214 : xsum (size_t size1, size_t size2)
56 : : {
57 : 214 : size_t sum = size1 + size2;
58 [ + - ]: 214 : return (sum >= size1 ? sum : SIZE_MAX);
59 : : }
60 : :
61 : : /* Sum of three sizes, with overflow check. */
62 : : static inline size_t
63 : : #if __GNUC__ >= 3
64 : : __attribute__ ((__pure__))
65 : : #endif
66 : : xsum3 (size_t size1, size_t size2, size_t size3)
67 : : {
68 : : return xsum (xsum (size1, size2), size3);
69 : : }
70 : :
71 : : /* Sum of four sizes, with overflow check. */
72 : : static inline size_t
73 : : #if __GNUC__ >= 3
74 : : __attribute__ ((__pure__))
75 : : #endif
76 : 36 : xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
77 : : {
78 : 36 : return xsum (xsum (xsum (size1, size2), size3), size4);
79 : : }
80 : :
81 : : /* Maximum of two sizes, with overflow check. */
82 : : static inline size_t
83 : : #if __GNUC__ >= 3
84 : : __attribute__ ((__pure__))
85 : : #endif
86 : 12 : xmax (size_t size1, size_t size2)
87 : : {
88 : : /* No explicit check is needed here, because for any n:
89 : : max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
90 : 12 : return (size1 >= size2 ? size1 : size2);
91 : : }
92 : :
93 : : /* Multiplication of a count with an element size, with overflow check.
94 : : The count must be >= 0 and the element size must be > 0.
95 : : This is a macro, not an inline function, so that it works correctly even
96 : : when N is of a wider type and N > SIZE_MAX. */
97 : : #define xtimes(N, ELSIZE) \
98 : : ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
99 : :
100 : : /* Check for overflow. */
101 : : #define size_overflow_p(SIZE) \
102 : : ((SIZE) == SIZE_MAX)
103 : : /* Check against overflow. */
104 : : #define size_in_bounds_p(SIZE) \
105 : : ((SIZE) != SIZE_MAX)
106 : :
107 : : #endif /* _XSIZE_H */
|