LibreOffice Module o3tl (master)  1
safeint.hxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #ifndef INCLUDED_O3TL_SAFEINT_HXX
11 #define INCLUDED_O3TL_SAFEINT_HXX
12 
13 #include <sal/config.h>
14 
15 #include <cassert>
16 #include <limits>
17 #include <type_traits>
18 
19 #if defined(_MSC_VER)
20 #include <safeint.h>
21 #else
22 #ifndef __has_builtin
23 # define __has_builtin(x) 0
24 #endif
25 #endif
26 
27 namespace o3tl
28 {
29 
30 template<typename T> inline
31 typename std::enable_if<std::is_signed<T>::value, T>::type saturating_add(
32  T a, T b)
33 {
34  if (b >= 0) {
35  if (a <= std::numeric_limits<T>::max() - b) {
36  return a + b;
37  } else {
38  return std::numeric_limits<T>::max();
39  }
40  } else {
41  if (a >= std::numeric_limits<T>::min() - b) {
42  return a + b;
43  } else {
44  return std::numeric_limits<T>::min();
45  }
46  }
47 }
48 
49 template<typename T> inline
50 typename std::enable_if<std::is_unsigned<T>::value, T>::type saturating_add(
51  T a, T b)
52 {
53  if (a <= std::numeric_limits<T>::max() - b) {
54  return a + b;
55  } else {
56  return std::numeric_limits<T>::max();
57  }
58 }
59 
60 template<typename T> inline
61 typename std::enable_if<std::is_signed<T>::value, T>::type saturating_sub(
62  T a, T b)
63 {
64  if (b >= 0) {
65  if (a >= std::numeric_limits<T>::min() + b) {
66  return a - b;
67  } else {
68  return std::numeric_limits<T>::min();
69  }
70  } else {
71  if (a <= std::numeric_limits<T>::max() + b) {
72  return a - b;
73  } else {
74  return std::numeric_limits<T>::max();
75  }
76  }
77 }
78 
79 template<typename T> inline
80 typename std::enable_if<std::is_unsigned<T>::value, T>::type saturating_sub(
81  T a, T b)
82 {
83  if (a >= std::numeric_limits<T>::min() + b) {
84  return a - b;
85  } else {
86  return std::numeric_limits<T>::min();
87  }
88 }
89 
90 template<typename T> inline
91 typename std::enable_if<std::is_signed<T>::value, T>::type saturating_toggle_sign(
92  T a)
93 {
94  if (a == std::numeric_limits<T>::min())
95  return std::numeric_limits<T>::max();
96  return a * -1;
97 }
98 
99 #if defined(_MSC_VER)
100 
101 template<typename T> inline bool checked_multiply(T a, T b, T& result)
102 {
103  return !msl::utilities::SafeMultiply(a, b, result);
104 }
105 
106 template<typename T> inline bool checked_add(T a, T b, T& result)
107 {
108  return !msl::utilities::SafeAdd(a, b, result);
109 }
110 
111 template<typename T> inline bool checked_sub(T a, T b, T& result)
112 {
113  return !msl::utilities::SafeSubtract(a, b, result);
114 }
115 
116 #elif (defined __GNUC__ && !defined __clang__) || (__has_builtin(__builtin_mul_overflow) && !(defined ANDROID && defined __clang__) && !(defined(__clang__) && defined(__i386__)))
117 // 32-bit clang fails with undefined reference to `__mulodi4'
118 
119 template<typename T> inline bool checked_multiply(T a, T b, T& result)
120 {
121  return __builtin_mul_overflow(a, b, &result);
122 }
123 
124 template<typename T> inline bool checked_add(T a, T b, T& result)
125 {
126  return __builtin_add_overflow(a, b, &result);
127 }
128 
129 template<typename T> inline bool checked_sub(T a, T b, T& result)
130 {
131  return __builtin_sub_overflow(a, b, &result);
132 }
133 
134 #else
135 
136 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
137 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_multiply(T a, T b, T& result)
138 {
139  if (a > 0) { /* a is positive */
140  if (b > 0) { /* a and b are positive */
141  if (a > (std::numeric_limits<T>::max() / b)) {
142  return true; /* Handle error */
143  }
144  } else { /* a positive, b nonpositive */
145  if (b < (std::numeric_limits<T>::min() / a)) {
146  return true; /* Handle error */
147  }
148  } /* a positive, b nonpositive */
149  } else { /* a is nonpositive */
150  if (b > 0) { /* a is nonpositive, b is positive */
151  if (a < (std::numeric_limits<T>::min() / b)) {
152  return true; /* Handle error */
153  }
154  } else { /* a and b are nonpositive */
155  if ( (a != 0) && (b < (std::numeric_limits<T>::max() / a))) {
156  return true; /* Handle error */
157  }
158  } /* End if a and b are nonpositive */
159  } /* End if a is nonpositive */
160 
161  result = a * b;
162 
163  return false;
164 }
165 
166 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
167 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_multiply(T a, T b, T& result)
168 {
169  if (b && a > std::numeric_limits<T>::max() / b) {
170  return true;/* Handle error */
171  }
172 
173  result = a * b;
174 
175  return false;
176 }
177 
178 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
179 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_add(T a, T b, T& result)
180 {
181  if (((b > 0) && (a > (std::numeric_limits<T>::max() - b))) ||
182  ((b < 0) && (a < (std::numeric_limits<T>::min() - b)))) {
183  return true;
184  }
185 
186  result = a + b;
187 
188  return false;
189 }
190 
191 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
192 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_add(T a, T b, T& result)
193 {
194  if (std::numeric_limits<T>::max() - a < b) {
195  return true;/* Handle error */
196  }
197 
198  result = a + b;
199 
200  return false;
201 }
202 
203 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
204 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_sub(T a, T b, T& result)
205 {
206  if ((b > 0 && a < std::numeric_limits<T>::min() + b) ||
207  (b < 0 && a > std::numeric_limits<T>::max() + b)) {
208  return true;
209  }
210 
211  result = a - b;
212 
213  return false;
214 }
215 
216 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
217 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_sub(T a, T b, T& result)
218 {
219  if (a < b) {
220  return true;
221  }
222 
223  result = a - b;
224 
225  return false;
226 }
227 
228 #endif
229 
230 template<typename T> constexpr std::enable_if_t<std::is_signed_v<T>, std::make_unsigned_t<T>>
232 {
233  assert(value >= 0);
234  return value;
235 }
236 
237 }
238 
239 #endif
240 
241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::enable_if< std::is_signed< T >::value, bool >::type checked_sub(T a, T b, T &result)
Definition: safeint.hxx:204
std::enable_if< std::is_signed< T >::value, T >::type saturating_sub(T a, T b)
Definition: safeint.hxx:61
std::enable_if< std::is_signed< T >::value, T >::type saturating_toggle_sign(T a)
Definition: safeint.hxx:91
std::enable_if< std::is_signed< T >::value, T >::type saturating_add(T a, T b)
Definition: safeint.hxx:31
std::enable_if< std::is_signed< T >::value, bool >::type checked_add(T a, T b, T &result)
Definition: safeint.hxx:179
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
Definition: safeint.hxx:231
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
Definition: safeint.hxx:137