Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: base/numerics/safe_math_impl.h

Issue 2318713004: Fix undefined behavior in base/numerics (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ 5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 216
217 } else { 217 } else {
218 if (y > 0) 218 if (y > 0)
219 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID 219 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
220 : RANGE_UNDERFLOW; 220 : RANGE_UNDERFLOW;
221 else 221 else
222 *validity = 222 *validity =
223 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; 223 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
224 } 224 }
225 225
226 return static_cast<T>(x * y); 226 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0);
227 } 227 }
228 228
229 template <typename T> 229 template <typename T>
230 typename std::enable_if<std::numeric_limits<T>::is_integer && 230 typename std::enable_if<std::numeric_limits<T>::is_integer &&
231 !std::numeric_limits<T>::is_signed && 231 !std::numeric_limits<T>::is_signed &&
232 (sizeof(T) * 2 > sizeof(uintmax_t)), 232 (sizeof(T) * 2 > sizeof(uintmax_t)),
233 T>::type 233 T>::type
234 CheckedMul(T x, T y, RangeConstraint* validity) { 234 CheckedMul(T x, T y, RangeConstraint* validity) {
235 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) 235 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
236 ? RANGE_VALID 236 ? RANGE_VALID
237 : RANGE_OVERFLOW; 237 : RANGE_OVERFLOW;
238 return static_cast<T>(x * y); 238 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0);
239 } 239 }
240 240
241 // Division just requires a check for an invalid negation on signed min/-1. 241 // Division just requires a check for an invalid negation on signed min/-1.
242 template <typename T> 242 template <typename T>
243 T CheckedDiv(T x, 243 T CheckedDiv(T x,
244 T y, 244 T y,
245 RangeConstraint* validity, 245 RangeConstraint* validity,
246 typename std::enable_if<std::numeric_limits<T>::is_integer, 246 typename std::enable_if<std::numeric_limits<T>::is_integer,
247 int>::type = 0) { 247 int>::type = 0) {
248 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && 248 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
249 y == static_cast<T>(-1)) { 249 y == static_cast<T>(-1)) {
250 *validity = RANGE_OVERFLOW; 250 *validity = RANGE_OVERFLOW;
251 return std::numeric_limits<T>::min(); 251 return std::numeric_limits<T>::min();
252 } 252 }
253 253
254 *validity = RANGE_VALID; 254 *validity = RANGE_VALID;
255 return static_cast<T>(x / y); 255 return static_cast<T>(x / y);
256 } 256 }
257 257
258 template <typename T> 258 template <typename T>
259 typename std::enable_if<std::numeric_limits<T>::is_integer && 259 typename std::enable_if<std::numeric_limits<T>::is_integer &&
260 std::numeric_limits<T>::is_signed, 260 std::numeric_limits<T>::is_signed,
261 T>::type 261 T>::type
262 CheckedMod(T x, T y, RangeConstraint* validity) { 262 CheckedMod(T x, T y, RangeConstraint* validity) {
263 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; 263 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
264 return static_cast<T>(x % y); 264 return static_cast<T>(*validity == RANGE_VALID ? x % y: 0);
265 } 265 }
266 266
267 template <typename T> 267 template <typename T>
268 typename std::enable_if<std::numeric_limits<T>::is_integer && 268 typename std::enable_if<std::numeric_limits<T>::is_integer &&
269 !std::numeric_limits<T>::is_signed, 269 !std::numeric_limits<T>::is_signed,
270 T>::type 270 T>::type
271 CheckedMod(T x, T y, RangeConstraint* validity) { 271 CheckedMod(T x, T y, RangeConstraint* validity) {
272 *validity = RANGE_VALID; 272 *validity = RANGE_VALID;
273 return static_cast<T>(x % y); 273 return static_cast<T>(x % y);
274 } 274 }
275 275
276 template <typename T> 276 template <typename T>
277 typename std::enable_if<std::numeric_limits<T>::is_integer && 277 typename std::enable_if<std::numeric_limits<T>::is_integer &&
278 std::numeric_limits<T>::is_signed, 278 std::numeric_limits<T>::is_signed,
279 T>::type 279 T>::type
280 CheckedNeg(T value, RangeConstraint* validity) { 280 CheckedNeg(T value, RangeConstraint* validity) {
281 *validity = 281 *validity =
282 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; 282 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
283 // The negation of signed min is min, so catch that one. 283 // The negation of signed min is min, so catch that one.
284 return static_cast<T>(-value); 284 return static_cast<T>(*validity == RANGE_VALID ? -value : 0);
285 } 285 }
286 286
287 template <typename T> 287 template <typename T>
288 typename std::enable_if<std::numeric_limits<T>::is_integer && 288 typename std::enable_if<std::numeric_limits<T>::is_integer &&
289 !std::numeric_limits<T>::is_signed, 289 !std::numeric_limits<T>::is_signed,
290 T>::type 290 T>::type
291 CheckedNeg(T value, RangeConstraint* validity) { 291 CheckedNeg(T value, RangeConstraint* validity) {
292 // The only legal unsigned negation is zero. 292 // The only legal unsigned negation is zero.
293 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; 293 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
294 return static_cast<T>( 294 return static_cast<T>(*validity == RANGE_VALID ?
295 -static_cast<typename SignedIntegerForSize<T>::type>(value)); 295 -static_cast<typename SignedIntegerForSize<T>::type>(value) : 0);
296 } 296 }
297 297
298 template <typename T> 298 template <typename T>
299 typename std::enable_if<std::numeric_limits<T>::is_integer && 299 typename std::enable_if<std::numeric_limits<T>::is_integer &&
300 std::numeric_limits<T>::is_signed, 300 std::numeric_limits<T>::is_signed,
301 T>::type 301 T>::type
302 CheckedAbs(T value, RangeConstraint* validity) { 302 CheckedAbs(T value, RangeConstraint* validity) {
303 *validity = 303 *validity =
304 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; 304 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
305 return static_cast<T>(std::abs(value)); 305 return static_cast<T>(*validity == RANGE_VALID ? std::abs(value) : 0);
306 } 306 }
307 307
308 template <typename T> 308 template <typename T>
309 typename std::enable_if<std::numeric_limits<T>::is_integer && 309 typename std::enable_if<std::numeric_limits<T>::is_integer &&
310 !std::numeric_limits<T>::is_signed, 310 !std::numeric_limits<T>::is_signed,
311 T>::type 311 T>::type
312 CheckedAbs(T value, RangeConstraint* validity) { 312 CheckedAbs(T value, RangeConstraint* validity) {
313 // T is unsigned, so |value| must already be positive. 313 // T is unsigned, so |value| must already be positive.
314 *validity = RANGE_VALID; 314 *validity = RANGE_VALID;
315 return value; 315 return value;
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 sizeof(T) >= (2 * sizeof(Lhs)) && 523 sizeof(T) >= (2 * sizeof(Lhs)) &&
524 StaticDstRangeRelationToSrcRange<T, Rhs>::value != 524 StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
525 NUMERIC_RANGE_CONTAINED && 525 NUMERIC_RANGE_CONTAINED &&
526 sizeof(T) >= (2 * sizeof(Rhs)); 526 sizeof(T) >= (2 * sizeof(Rhs));
527 }; 527 };
528 528
529 } // namespace internal 529 } // namespace internal
530 } // namespace base 530 } // namespace base
531 531
532 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 532 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « no previous file | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698