Line data Source code
1 : /* xsize.h -- Checked size_t computations.
2 :
3 : Copyright (C) 2003, 2008-2016 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 : #ifndef _GL_INLINE_HEADER_BEGIN
31 : #error "Please include config.h first."
32 : #endif
33 : _GL_INLINE_HEADER_BEGIN
34 : #ifndef XSIZE_INLINE
35 : # define XSIZE_INLINE _GL_INLINE
36 : #endif
37 :
38 : /* The size of memory objects is often computed through expressions of
39 : type size_t. Example:
40 : void* p = malloc (header_size + n * element_size).
41 : These computations can lead to overflow. When this happens, malloc()
42 : returns a piece of memory that is way too small, and the program then
43 : crashes while attempting to fill the memory.
44 : To avoid this, the functions and macros in this file check for overflow.
45 : The convention is that SIZE_MAX represents overflow.
46 : malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
47 : implementation that uses mmap --, it's recommended to use size_overflow_p()
48 : or size_in_bounds_p() before invoking malloc().
49 : The example thus becomes:
50 : size_t size = xsum (header_size, xtimes (n, element_size));
51 : void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
52 : */
53 :
54 : /* Convert an arbitrary value >= 0 to type size_t. */
55 : #define xcast_size_t(N) \
56 : ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
57 :
58 : /* Sum of two sizes, with overflow check. */
59 : XSIZE_INLINE size_t
60 : #if __GNUC__ >= 3
61 : __attribute__ ((__pure__))
62 : #endif
63 0 : xsum (size_t size1, size_t size2)
64 : {
65 0 : size_t sum = size1 + size2;
66 0 : return (sum >= size1 ? sum : SIZE_MAX);
67 : }
68 :
69 : /* Sum of three sizes, with overflow check. */
70 : XSIZE_INLINE size_t
71 : #if __GNUC__ >= 3
72 : __attribute__ ((__pure__))
73 : #endif
74 0 : xsum3 (size_t size1, size_t size2, size_t size3)
75 : {
76 0 : return xsum (xsum (size1, size2), size3);
77 : }
78 :
79 : /* Sum of four sizes, with overflow check. */
80 : XSIZE_INLINE size_t
81 : #if __GNUC__ >= 3
82 : __attribute__ ((__pure__))
83 : #endif
84 0 : xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
85 : {
86 0 : return xsum (xsum (xsum (size1, size2), size3), size4);
87 : }
88 :
89 : /* Maximum of two sizes, with overflow check. */
90 : XSIZE_INLINE size_t
91 : #if __GNUC__ >= 3
92 : __attribute__ ((__pure__))
93 : #endif
94 0 : xmax (size_t size1, size_t size2)
95 : {
96 : /* No explicit check is needed here, because for any n:
97 : max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
98 0 : return (size1 >= size2 ? size1 : size2);
99 : }
100 :
101 : /* Multiplication of a count with an element size, with overflow check.
102 : The count must be >= 0 and the element size must be > 0.
103 : This is a macro, not a function, so that it works correctly even
104 : when N is of a wider type and N > SIZE_MAX. */
105 : #define xtimes(N, ELSIZE) \
106 : ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
107 :
108 : /* Check for overflow. */
109 : #define size_overflow_p(SIZE) \
110 : ((SIZE) == SIZE_MAX)
111 : /* Check against overflow. */
112 : #define size_in_bounds_p(SIZE) \
113 : ((SIZE) != SIZE_MAX)
114 :
115 : _GL_INLINE_HEADER_END
116 :
117 : #endif /* _XSIZE_H */
|