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

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

Issue 2441753003: Fix some div by 0s in safe_math_impl.h (Closed)
Patch Set: Remove stray code from unrelated change Created 4 years, 1 month 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 | no next file » | 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 PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ 5 #ifndef PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_
6 #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ 6 #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_
7 7
8 #include <stddef.h>
8 #include <stdint.h> 9 #include <stdint.h>
9 10
11 #include <climits>
10 #include <cmath> 12 #include <cmath>
11 #include <cstdlib> 13 #include <cstdlib>
12 #include <limits> 14 #include <limits>
13 #include <type_traits> 15 #include <type_traits>
14 16
15 #include "safe_conversions.h" 17 #include "safe_conversions.h"
16 #include "third_party/base/macros.h" 18 #include "third_party/base/macros.h"
17 19
18 namespace pdfium { 20 namespace pdfium {
19 namespace base { 21 namespace base {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 std::numeric_limits<Integer>::is_integer, 85 std::numeric_limits<Integer>::is_integer,
84 typename IntegerForSizeAndSign< 86 typename IntegerForSizeAndSign<
85 sizeof(Integer) * 2, 87 sizeof(Integer) * 2,
86 std::numeric_limits<Integer>::is_signed>::type>::type type; 88 std::numeric_limits<Integer>::is_signed>::type>::type type;
87 }; 89 };
88 90
89 template <typename Integer> 91 template <typename Integer>
90 struct PositionOfSignBit { 92 struct PositionOfSignBit {
91 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, 93 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
92 size_t>::type value = 94 size_t>::type value =
93 8 * sizeof(Integer) - 1; 95 CHAR_BIT * sizeof(Integer) - 1;
94 }; 96 };
95 97
96 // Helper templates for integer manipulations. 98 // Helper templates for integer manipulations.
97 99
98 template <typename T> 100 template <typename T>
99 bool HasSignBit(T x) { 101 constexpr bool HasSignBit(T x) {
100 // Cast to unsigned since right shift on signed is undefined. 102 // Cast to unsigned since right shift on signed is undefined.
101 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> 103 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
102 PositionOfSignBit<T>::value); 104 PositionOfSignBit<T>::value);
103 } 105 }
104 106
105 // This wrapper undoes the standard integer promotions. 107 // This wrapper undoes the standard integer promotions.
106 template <typename T> 108 template <typename T>
107 T BinaryComplement(T x) { 109 constexpr T BinaryComplement(T x) {
108 return ~x; 110 return static_cast<T>(~x);
109 } 111 }
110 112
111 // Here are the actual portable checked integer math implementations. 113 // Here are the actual portable checked integer math implementations.
112 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean 114 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean
113 // way to coalesce things into the CheckedNumericState specializations below. 115 // way to coalesce things into the CheckedNumericState specializations below.
114 116
115 template <typename T> 117 template <typename T>
116 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type 118 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
117 CheckedAdd(T x, T y, RangeConstraint* validity) { 119 CheckedAdd(T x, T y, RangeConstraint* validity) {
118 // Since the value of x+y is undefined if we have a signed type, we compute 120 // Since the value of x+y is undefined if we have a signed type, we compute
119 // it using the unsigned type of the same size. 121 // it using the unsigned type of the same size.
120 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; 122 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
121 UnsignedDst ux = static_cast<UnsignedDst>(x); 123 UnsignedDst ux = static_cast<UnsignedDst>(x);
122 UnsignedDst uy = static_cast<UnsignedDst>(y); 124 UnsignedDst uy = static_cast<UnsignedDst>(y);
123 UnsignedDst uresult = ux + uy; 125 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
124 // Addition is valid if the sign of (x + y) is equal to either that of x or 126 // Addition is valid if the sign of (x + y) is equal to either that of x or
125 // that of y. 127 // that of y.
126 if (std::numeric_limits<T>::is_signed) { 128 if (std::numeric_limits<T>::is_signed) {
127 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) 129 if (HasSignBit(BinaryComplement(
130 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))))) {
128 *validity = RANGE_VALID; 131 *validity = RANGE_VALID;
129 else // Direction of wrap is inverse of result sign. 132 } else { // Direction of wrap is inverse of result sign.
130 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; 133 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
131 134 }
132 } else { // Unsigned is either valid or overflow. 135 } else { // Unsigned is either valid or overflow.
133 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; 136 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
134 } 137 }
135 return static_cast<T>(uresult); 138 return static_cast<T>(uresult);
136 } 139 }
137 140
138 template <typename T> 141 template <typename T>
139 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type 142 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
140 CheckedSub(T x, T y, RangeConstraint* validity) { 143 CheckedSub(T x, T y, RangeConstraint* validity) {
141 // Since the value of x+y is undefined if we have a signed type, we compute 144 // Since the value of x+y is undefined if we have a signed type, we compute
142 // it using the unsigned type of the same size. 145 // it using the unsigned type of the same size.
143 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; 146 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
144 UnsignedDst ux = static_cast<UnsignedDst>(x); 147 UnsignedDst ux = static_cast<UnsignedDst>(x);
145 UnsignedDst uy = static_cast<UnsignedDst>(y); 148 UnsignedDst uy = static_cast<UnsignedDst>(y);
146 UnsignedDst uresult = ux - uy; 149 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
147 // Subtraction is valid if either x and y have same sign, or (x-y) and x have 150 // Subtraction is valid if either x and y have same sign, or (x-y) and x have
148 // the same sign. 151 // the same sign.
149 if (std::numeric_limits<T>::is_signed) { 152 if (std::numeric_limits<T>::is_signed) {
150 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) 153 if (HasSignBit(BinaryComplement(
154 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))))) {
151 *validity = RANGE_VALID; 155 *validity = RANGE_VALID;
152 else // Direction of wrap is inverse of result sign. 156 } else { // Direction of wrap is inverse of result sign.
153 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; 157 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
154 158 }
155 } else { // Unsigned is either valid or underflow. 159 } else { // Unsigned is either valid or underflow.
156 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; 160 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
157 } 161 }
158 return static_cast<T>(uresult); 162 return static_cast<T>(uresult);
159 } 163 }
160 164
161 // Integer multiplication is a bit complicated. In the fast case we just 165 // Integer multiplication is a bit complicated. In the fast case we just
162 // we just promote to a twice wider type, and range check the result. In the 166 // we just promote to a twice wider type, and range check the result. In the
163 // slow case we need to manually check that the result won't be truncated by 167 // slow case we need to manually check that the result won't be truncated by
164 // checking with division against the appropriate bound. 168 // checking with division against the appropriate bound.
(...skipping 10 matching lines...) Expand all
175 } 179 }
176 180
177 template <typename T> 181 template <typename T>
178 typename std::enable_if<std::numeric_limits<T>::is_integer && 182 typename std::enable_if<std::numeric_limits<T>::is_integer &&
179 std::numeric_limits<T>::is_signed && 183 std::numeric_limits<T>::is_signed &&
180 (sizeof(T) * 2 > sizeof(uintmax_t)), 184 (sizeof(T) * 2 > sizeof(uintmax_t)),
181 T>::type 185 T>::type
182 CheckedMul(T x, T y, RangeConstraint* validity) { 186 CheckedMul(T x, T y, RangeConstraint* validity) {
183 // If either side is zero then the result will be zero. 187 // If either side is zero then the result will be zero.
184 if (!x || !y) { 188 if (!x || !y) {
185 return RANGE_VALID; 189 *validity = RANGE_VALID;
186 190 return static_cast<T>(0);
187 } else if (x > 0) { 191 }
188 if (y > 0) 192 if (x > 0) {
193 if (y > 0) {
189 *validity = 194 *validity =
190 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; 195 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
191 else 196 } else {
192 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID 197 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
193 : RANGE_UNDERFLOW; 198 : RANGE_UNDERFLOW;
194 199 }
195 } else { 200 } else {
196 if (y > 0) 201 if (y > 0) {
197 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID 202 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
198 : RANGE_UNDERFLOW; 203 : RANGE_UNDERFLOW;
199 else 204 } else {
200 *validity = 205 *validity =
201 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; 206 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
207 }
202 } 208 }
203 209 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0);
204 return x * y;
205 } 210 }
206 211
207 template <typename T> 212 template <typename T>
208 typename std::enable_if<std::numeric_limits<T>::is_integer && 213 typename std::enable_if<std::numeric_limits<T>::is_integer &&
209 !std::numeric_limits<T>::is_signed && 214 !std::numeric_limits<T>::is_signed &&
210 (sizeof(T) * 2 > sizeof(uintmax_t)), 215 (sizeof(T) * 2 > sizeof(uintmax_t)),
211 T>::type 216 T>::type
212 CheckedMul(T x, T y, RangeConstraint* validity) { 217 CheckedMul(T x, T y, RangeConstraint* validity) {
213 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) 218 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
214 ? RANGE_VALID 219 ? RANGE_VALID
215 : RANGE_OVERFLOW; 220 : RANGE_OVERFLOW;
216 return x * y; 221 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0);
217 } 222 }
218 223
219 // Division just requires a check for an invalid negation on signed min/-1. 224 // Division just requires a check for a zero denominator or an invalid negation
225 // on signed min/-1.
220 template <typename T> 226 template <typename T>
221 T CheckedDiv(T x, 227 T CheckedDiv(T x,
222 T y, 228 T y,
223 RangeConstraint* validity, 229 RangeConstraint* validity,
224 typename std::enable_if<std::numeric_limits<T>::is_integer, 230 typename std::enable_if<std::numeric_limits<T>::is_integer,
225 int>::type = 0) { 231 int>::type = 0) {
232 if (y == 0) {
233 *validity = RANGE_INVALID;
234 return static_cast<T>(0);
235 }
226 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && 236 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
227 y == static_cast<T>(-1)) { 237 y == static_cast<T>(-1)) {
228 *validity = RANGE_OVERFLOW; 238 *validity = RANGE_OVERFLOW;
229 return std::numeric_limits<T>::min(); 239 return std::numeric_limits<T>::min();
230 } 240 }
231
232 *validity = RANGE_VALID; 241 *validity = RANGE_VALID;
233 return x / y; 242 return static_cast<T>(x / y);
234 } 243 }
235 244
236 template <typename T> 245 template <typename T>
237 typename std::enable_if<std::numeric_limits<T>::is_integer && 246 typename std::enable_if<std::numeric_limits<T>::is_integer &&
238 std::numeric_limits<T>::is_signed, 247 std::numeric_limits<T>::is_signed,
239 T>::type 248 T>::type
240 CheckedMod(T x, T y, RangeConstraint* validity) { 249 CheckedMod(T x, T y, RangeConstraint* validity) {
241 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; 250 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
242 return x % y; 251 return static_cast<T>(*validity == RANGE_VALID ? x % y : 0);
243 } 252 }
244 253
245 template <typename T> 254 template <typename T>
246 typename std::enable_if<std::numeric_limits<T>::is_integer && 255 typename std::enable_if<std::numeric_limits<T>::is_integer &&
247 !std::numeric_limits<T>::is_signed, 256 !std::numeric_limits<T>::is_signed,
248 T>::type 257 T>::type
249 CheckedMod(T x, T y, RangeConstraint* validity) { 258 CheckedMod(T x, T y, RangeConstraint* validity) {
250 *validity = RANGE_VALID; 259 *validity = y != 0 ? RANGE_VALID : RANGE_INVALID;
251 return x % y; 260 return static_cast<T>(*validity == RANGE_VALID ? x % y : 0);
252 } 261 }
253 262
254 template <typename T> 263 template <typename T>
255 typename std::enable_if<std::numeric_limits<T>::is_integer && 264 typename std::enable_if<std::numeric_limits<T>::is_integer &&
256 std::numeric_limits<T>::is_signed, 265 std::numeric_limits<T>::is_signed,
257 T>::type 266 T>::type
258 CheckedNeg(T value, RangeConstraint* validity) { 267 CheckedNeg(T value, RangeConstraint* validity) {
259 *validity = 268 *validity =
260 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; 269 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
261 // The negation of signed min is min, so catch that one. 270 // The negation of signed min is min, so catch that one.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 return value; 302 return value;
294 } 303 }
295 304
296 // These are the floating point stubs that the compiler needs to see. Only the 305 // These are the floating point stubs that the compiler needs to see. Only the
297 // negation operation is ever called. 306 // negation operation is ever called.
298 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ 307 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
299 template <typename T> \ 308 template <typename T> \
300 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ 309 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
301 Checked##NAME(T, T, RangeConstraint*) { \ 310 Checked##NAME(T, T, RangeConstraint*) { \
302 NOTREACHED(); \ 311 NOTREACHED(); \
303 return 0; \ 312 return static_cast<T>(0); \
304 } 313 }
305 314
306 BASE_FLOAT_ARITHMETIC_STUBS(Add) 315 BASE_FLOAT_ARITHMETIC_STUBS(Add)
307 BASE_FLOAT_ARITHMETIC_STUBS(Sub) 316 BASE_FLOAT_ARITHMETIC_STUBS(Sub)
308 BASE_FLOAT_ARITHMETIC_STUBS(Mul) 317 BASE_FLOAT_ARITHMETIC_STUBS(Mul)
309 BASE_FLOAT_ARITHMETIC_STUBS(Div) 318 BASE_FLOAT_ARITHMETIC_STUBS(Div)
310 BASE_FLOAT_ARITHMETIC_STUBS(Mod) 319 BASE_FLOAT_ARITHMETIC_STUBS(Mod)
311 320
312 #undef BASE_FLOAT_ARITHMETIC_STUBS 321 #undef BASE_FLOAT_ARITHMETIC_STUBS
313 322
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 StaticDstRangeRelationToSrcRange<T, Rhs>::value != 507 StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
499 NUMERIC_RANGE_CONTAINED && 508 NUMERIC_RANGE_CONTAINED &&
500 sizeof(T) >= (2 * sizeof(Rhs)); 509 sizeof(T) >= (2 * sizeof(Rhs));
501 }; 510 };
502 511
503 } // namespace internal 512 } // namespace internal
504 } // namespace base 513 } // namespace base
505 } // namespace pdfium 514 } // namespace pdfium
506 515
507 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ 516 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698