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

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

Issue 2528243002: Fix silent truncations when extracting values from CheckedNumeric (Closed)
Patch Set: compile fix Created 4 years 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 | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_math_impl.h » ('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_H_ 5 #ifndef BASE_NUMERICS_SAFE_MATH_H_
6 #define BASE_NUMERICS_SAFE_MATH_H_ 6 #define BASE_NUMERICS_SAFE_MATH_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 9
10 #include <limits> 10 #include <limits>
11 #include <type_traits> 11 #include <type_traits>
12 12
13 #include "base/numerics/safe_math_impl.h" 13 #include "base/numerics/safe_math_impl.h"
14 14
15 namespace base { 15 namespace base {
16 namespace internal { 16 namespace internal {
17 17
18 // CheckedNumeric implements all the logic and operators for detecting integer 18 // CheckedNumeric<> implements all the logic and operators for detecting integer
19 // boundary conditions such as overflow, underflow, and invalid conversions. 19 // boundary conditions such as overflow, underflow, and invalid conversions.
20 // The CheckedNumeric type implicitly converts from floating point and integer 20 // The CheckedNumeric type implicitly converts from floating point and integer
21 // data types, and contains overloads for basic arithmetic operations (i.e.: +, 21 // data types, and contains overloads for basic arithmetic operations (i.e.: +,
22 // -, *, / for all types and %, <<, >>, &, |, ^ for integers; additionally the 22 // -, *, / for all types and %, <<, >>, &, |, ^ for integers; additionally the
23 // result of all bitwise logical operations is always promoted to an unsigned 23 // result of all bitwise logical operations is always promoted to an unsigned
24 // CheckedNumeric type matching the width of the larger operand). 24 // CheckedNumeric type matching the width of the larger operand).
25 // 25 //
26 // You may also use one of the variadic convenience functions, which accept 26 // You may also use one of the variadic convenience functions, which accept
27 // standard arithmetic or CheckedNumeric types, perform arithmetic operations, 27 // standard arithmetic or CheckedNumeric types, perform arithmetic operations,
28 // and return a CheckedNumeric result. The supported functions are: 28 // and return a CheckedNumeric result. The supported functions are:
29 // CheckAdd() - Addition. 29 // CheckAdd() - Addition.
30 // CheckSub() - Subtraction. 30 // CheckSub() - Subtraction.
31 // CheckMul() - Multiplication. 31 // CheckMul() - Multiplication.
32 // CheckDiv() - Division. 32 // CheckDiv() - Division.
33 // CheckMod() - Modulous (integer only). 33 // CheckMod() - Modulous (integer only).
34 // CheckLsh() - Left integer shift (integer only). 34 // CheckLsh() - Left integer shift (integer only).
35 // CheckRsh() - Right integer shift (integer only). 35 // CheckRsh() - Right integer shift (integer only).
36 // CheckAnd() - Bitwise AND (integer only with unsigned result).
37 // CheckOr() - Bitwise OR (integer only with unsigned result).
38 // CheckXor() - Bitwise XOR (integer only with unsigned result).
36 // 39 //
37 // The unary negation, increment, and decrement operators are supported, along 40 // The unary negation, increment, and decrement operators are supported, along
38 // with the following unary arithmetic methods, which return a new 41 // with the following unary arithmetic methods, which return a new
39 // CheckedNumeric as a result of the operation: 42 // CheckedNumeric as a result of the operation:
40 // Abs() - Absolute value. 43 // Abs() - Absolute value.
41 // UnsignedAbs() - Absolute value as an equival-width unsigned underlying type 44 // UnsignedAbs() - Absolute value as an equival-width unsigned underlying type
42 // (valid for only integral types). 45 // (valid for only integral types).
43 // 46 //
44 // The following methods convert from CheckedNumeric to standard numeric values: 47 // The following methods convert from CheckedNumeric to standard numeric values:
48 // AssignIfValid() - Assigns the underlying value to the supplied destination
49 // pointer if the value is currently valid and within the range
50 // supported by the destination type. Returns true on success.
51 // ****************************************************************************
52 // * WARNING: All of the following functions return a StrictNumeric, which *
53 // * is valid for comparison and assignment operations, but will trigger a *
54 // * compile failure on attempts to assign to a type of insufficient range. *
55 // ****************************************************************************
45 // IsValid() - Returns true if the underlying numeric value is valid (i.e. has 56 // IsValid() - Returns true if the underlying numeric value is valid (i.e. has
46 // has not wrapped and is not the result of an invalid conversion). 57 // has not wrapped and is not the result of an invalid conversion).
47 // AssignIfValid() - Assigns the underlying value to the supplied destination
48 // pointer if the value is currently valid and within the range
49 // supported by the destination type. Returns true on success.
50 // ValueOrDie() - Returns the underlying value. If the state is not valid this 58 // ValueOrDie() - Returns the underlying value. If the state is not valid this
51 // call will crash on a CHECK. 59 // call will crash on a CHECK.
52 // ValueOrDefault() - Returns the current value, or the supplied default if the 60 // ValueOrDefault() - Returns the current value, or the supplied default if the
53 // state is not valid (will not trigger a CHECK). 61 // state is not valid (will not trigger a CHECK).
54 // ValueFloating() - Returns the underlying floating point value (valid only 62 //
55 // for floating point CheckedNumeric types; will not cause a CHECK). 63 // The following wrapper functions can be used to avoid the template
64 // disambiguator syntax when converting a destination type.
65 // IsValidForType<>() in place of: a.template IsValid<Dst>()
66 // ValueOrDieForType<>() in place of: a.template ValueOrDie()
67 // ValueOrDefaultForType<>() in place of: a.template ValueOrDefault(default)
56 // 68 //
57 // The following are general utility methods that are useful for converting 69 // The following are general utility methods that are useful for converting
58 // between arithmetic types and CheckedNumeric types: 70 // between arithmetic types and CheckedNumeric types:
59 // CheckedNumeric::Cast<Dst>() - Instance method returning a CheckedNumeric 71 // CheckedNumeric::Cast<Dst>() - Instance method returning a CheckedNumeric
60 // derived from casting the current instance to a CheckedNumeric of 72 // derived from casting the current instance to a CheckedNumeric of
61 // the supplied destination type. 73 // the supplied destination type.
62 // CheckNum() - Creates a new CheckedNumeric from the underlying type of the 74 // CheckNum() - Creates a new CheckedNumeric from the underlying type of the
63 // supplied arithmetic or CheckedNumeric type. 75 // supplied arithmetic or CheckedNumeric type.
64 // 76 //
65 // Comparison operations are explicitly not supported because they could result 77 // Comparison operations are explicitly not supported because they could result
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 136
125 // ValueOrDie() - The primary accessor for the underlying value. If the 137 // ValueOrDie() - The primary accessor for the underlying value. If the
126 // current state is not valid it will CHECK and crash. 138 // current state is not valid it will CHECK and crash.
127 // A range checked destination type can be supplied using the Dst template 139 // A range checked destination type can be supplied using the Dst template
128 // parameter, which will trigger a CHECK if the value is not in bounds for 140 // parameter, which will trigger a CHECK if the value is not in bounds for
129 // the destination. 141 // the destination.
130 // The CHECK behavior can be overridden by supplying a handler as a 142 // The CHECK behavior can be overridden by supplying a handler as a
131 // template parameter, for test code, etc. However, the handler cannot access 143 // template parameter, for test code, etc. However, the handler cannot access
132 // the underlying value, and it is not available through other means. 144 // the underlying value, and it is not available through other means.
133 template <typename Dst = T, class CheckHandler = CheckOnFailure> 145 template <typename Dst = T, class CheckHandler = CheckOnFailure>
134 constexpr Dst ValueOrDie() const { 146 constexpr StrictNumeric<Dst> ValueOrDie() const {
135 return IsValid<Dst>() ? state_.value() 147 return IsValid<Dst>() ? static_cast<Dst>(state_.value())
136 : CheckHandler::template HandleFailure<Dst>(); 148 : CheckHandler::template HandleFailure<Dst>();
137 } 149 }
138 150
139 // ValueOrDefault(T default_value) - A convenience method that returns the 151 // ValueOrDefault(T default_value) - A convenience method that returns the
140 // current value if the state is valid, and the supplied default_value for 152 // current value if the state is valid, and the supplied default_value for
141 // any other state. 153 // any other state.
142 // A range checked destination type can be supplied using the Dst template 154 // A range checked destination type can be supplied using the Dst template
143 // parameter. WARNING: This function may fail to compile or CHECK at runtime 155 // parameter. WARNING: This function may fail to compile or CHECK at runtime
144 // if the supplied default_value is not within range of the destination type. 156 // if the supplied default_value is not within range of the destination type.
145 template <typename Dst = T, typename Src> 157 template <typename Dst = T, typename Src>
146 constexpr Dst ValueOrDefault(const Src default_value) const { 158 constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const {
147 return IsValid<Dst>() ? state_.value() : checked_cast<Dst>(default_value); 159 return IsValid<Dst>() ? static_cast<Dst>(state_.value())
148 } 160 : checked_cast<Dst>(default_value);
149
150 // ValueFloating() - Since floating point values include their validity state,
151 // we provide an easy method for extracting them directly, without a risk of
152 // crashing on a CHECK.
153 // A range checked destination type can be supplied using the Dst template
154 // parameter.
155 template <typename Dst = T>
156 constexpr Dst ValueFloating() const {
157 static_assert(std::numeric_limits<T>::is_iec559,
158 "Type must be floating point.");
159 static_assert(std::numeric_limits<Dst>::is_iec559,
160 "Type must be floating point.");
161 return static_cast<Dst>(state_.value());
162 } 161 }
163 162
164 // Returns a checked numeric of the specified type, cast from the current 163 // Returns a checked numeric of the specified type, cast from the current
165 // CheckedNumeric. If the current state is invalid or the destination cannot 164 // CheckedNumeric. If the current state is invalid or the destination cannot
166 // represent the result then the returned CheckedNumeric will be invalid. 165 // represent the result then the returned CheckedNumeric will be invalid.
167 template <typename Dst> 166 template <typename Dst>
168 constexpr CheckedNumeric<typename UnderlyingType<Dst>::type> Cast() const { 167 constexpr CheckedNumeric<typename UnderlyingType<Dst>::type> Cast() const {
169 return *this; 168 return *this;
170 } 169 }
171 170
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 struct Wrapper<CheckedNumeric<Src>> { 294 struct Wrapper<CheckedNumeric<Src>> {
296 static constexpr bool is_valid(const CheckedNumeric<Src>& v) { 295 static constexpr bool is_valid(const CheckedNumeric<Src>& v) {
297 return v.IsValid(); 296 return v.IsValid();
298 } 297 }
299 static constexpr Src value(const CheckedNumeric<Src>& v) { 298 static constexpr Src value(const CheckedNumeric<Src>& v) {
300 return v.state_.value(); 299 return v.state_.value();
301 } 300 }
302 }; 301 };
303 }; 302 };
304 303
304 // Convenience functions to avoid the ugly template disambiguator syntax.
305 template <typename Dst, typename Src>
306 constexpr bool IsValidForType(const CheckedNumeric<Src> value) {
307 return value.template IsValid<Dst>();
308 }
309
310 template <typename Dst, typename Src>
311 constexpr StrictNumeric<Dst> ValueOrDieForType(
312 const CheckedNumeric<Src> value) {
313 return value.template ValueOrDie<Dst>();
314 }
315
316 template <typename Dst, typename Src, typename Default>
317 constexpr StrictNumeric<Dst> ValueOrDefaultForType(
318 const CheckedNumeric<Src> value,
319 const Default default_value) {
320 return value.template ValueOrDefault<Dst>(default_value);
321 }
322
305 // These variadic templates work out the return types. 323 // These variadic templates work out the return types.
306 // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support. 324 // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
307 template <template <typename, typename, typename> class M, 325 template <template <typename, typename, typename> class M,
308 typename L, 326 typename L,
309 typename R, 327 typename R,
310 typename... Args> 328 typename... Args>
311 struct ResultType; 329 struct ResultType;
312 330
313 template <template <typename, typename, typename> class M, 331 template <template <typename, typename, typename> class M,
314 typename L, 332 typename L,
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) 405 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=)
388 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) 406 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=)
389 BASE_NUMERIC_ARITHMETIC_OPERATORS(Lsh, <<, <<=) 407 BASE_NUMERIC_ARITHMETIC_OPERATORS(Lsh, <<, <<=)
390 BASE_NUMERIC_ARITHMETIC_OPERATORS(Rsh, >>, >>=) 408 BASE_NUMERIC_ARITHMETIC_OPERATORS(Rsh, >>, >>=)
391 BASE_NUMERIC_ARITHMETIC_OPERATORS(And, &, &=) 409 BASE_NUMERIC_ARITHMETIC_OPERATORS(And, &, &=)
392 BASE_NUMERIC_ARITHMETIC_OPERATORS(Or, |, |=) 410 BASE_NUMERIC_ARITHMETIC_OPERATORS(Or, |, |=)
393 BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=) 411 BASE_NUMERIC_ARITHMETIC_OPERATORS(Xor, ^, ^=)
394 412
395 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS 413 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
396 414
415 // These are some extra StrictNumeric operators to support simple pointer
416 // arithmetic with our result types. Since wrapping on a pointer is always
417 // bad, we trigger the CHECK condition here.
418 template <typename L, typename R>
419 L* operator+(L* lhs, const StrictNumeric<R> rhs) {
420 uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
421 CheckMul(sizeof(L), static_cast<R>(rhs)))
422 .template ValueOrDie<uintptr_t>();
423 return reinterpret_cast<L*>(result);
424 }
425
426 template <typename L, typename R>
427 L* operator-(L* lhs, const StrictNumeric<R> rhs) {
428 uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
429 CheckMul(sizeof(L), static_cast<R>(rhs)))
430 .template ValueOrDie<uintptr_t>();
431 return reinterpret_cast<L*>(result);
432 }
433
397 } // namespace internal 434 } // namespace internal
398 435
399 using internal::CheckedNumeric; 436 using internal::CheckedNumeric;
437 using internal::IsValidForType;
438 using internal::ValueOrDieForType;
439 using internal::ValueOrDefaultForType;
400 using internal::CheckNum; 440 using internal::CheckNum;
401 using internal::CheckAdd; 441 using internal::CheckAdd;
402 using internal::CheckSub; 442 using internal::CheckSub;
403 using internal::CheckMul; 443 using internal::CheckMul;
404 using internal::CheckDiv; 444 using internal::CheckDiv;
405 using internal::CheckMod; 445 using internal::CheckMod;
406 using internal::CheckLsh; 446 using internal::CheckLsh;
407 using internal::CheckRsh; 447 using internal::CheckRsh;
408 using internal::CheckAnd; 448 using internal::CheckAnd;
409 using internal::CheckOr; 449 using internal::CheckOr;
410 using internal::CheckXor; 450 using internal::CheckXor;
411 451
412 } // namespace base 452 } // namespace base
413 453
414 #endif // BASE_NUMERICS_SAFE_MATH_H_ 454 #endif // BASE_NUMERICS_SAFE_MATH_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_conversions_impl.h ('k') | base/numerics/safe_math_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698