1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_CHECKED_MATH_IMPL_H_
6 #define PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_CHECKED_MATH_IMPL_H_
7 
8 #include <climits>
9 #include <cmath>
10 #include <cstddef>
11 #include <cstdint>
12 #include <cstdlib>
13 #include <limits>
14 #include <type_traits>
15 
16 #include "partition_alloc/partition_alloc_base/numerics/safe_conversions.h"
17 #include "partition_alloc/partition_alloc_base/numerics/safe_math_shared_impl.h"
18 
19 namespace partition_alloc::internal::base::internal {
20 
21 template <typename T>
CheckedAddImpl(T x,T y,T * result)22 constexpr bool CheckedAddImpl(T x, T y, T* result) {
23   static_assert(std::is_integral_v<T>, "Type must be integral");
24   // Since the value of x+y is undefined if we have a signed type, we compute
25   // it using the unsigned type of the same size.
26   using UnsignedDst = typename std::make_unsigned<T>::type;
27   using SignedDst = typename std::make_signed<T>::type;
28   const UnsignedDst ux = static_cast<UnsignedDst>(x);
29   const UnsignedDst uy = static_cast<UnsignedDst>(y);
30   const UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
31   // Addition is valid if the sign of (x + y) is equal to either that of x or
32   // that of y.
33   if (std::is_signed_v<T>
34           ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) < 0
35           : uresult < uy) {  // Unsigned is either valid or underflow.
36     return false;
37   }
38   *result = static_cast<T>(uresult);
39   return true;
40 }
41 
42 template <typename T, typename U, class Enable = void>
43 struct CheckedAddOp {};
44 
45 template <typename T, typename U>
46 struct CheckedAddOp<T,
47                     U,
48                     typename std::enable_if<std::is_integral_v<T> &&
49                                             std::is_integral_v<U>>::type> {
50   using result_type = typename MaxExponentPromotion<T, U>::type;
51   template <typename V>
52   static constexpr bool Do(T x, U y, V* result) {
53     if constexpr (CheckedAddFastOp<T, U>::is_supported) {
54       return CheckedAddFastOp<T, U>::Do(x, y, result);
55     }
56 
57     // Double the underlying type up to a full machine word.
58     using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
59     using Promotion =
60         typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
61                                    IntegerBitsPlusSign<intptr_t>::value),
62                                   typename BigEnoughPromotion<T, U>::type,
63                                   FastPromotion>::type;
64     // Fail if either operand is out of range for the promoted type.
65     // TODO(jschuh): This could be made to work for a broader range of values.
66     if (PA_BASE_NUMERICS_UNLIKELY(
67             !IsValueInRangeForNumericType<Promotion>(x) ||
68             !IsValueInRangeForNumericType<Promotion>(y))) {
69       return false;
70     }
71 
72     Promotion presult = {};
73     bool is_valid = true;
74     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
75       presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
76     } else {
77       is_valid = CheckedAddImpl(static_cast<Promotion>(x),
78                                 static_cast<Promotion>(y), &presult);
79     }
80     if (!is_valid || !IsValueInRangeForNumericType<V>(presult)) {
81       return false;
82     }
83     *result = static_cast<V>(presult);
84     return true;
85   }
86 };
87 
88 template <typename T>
89 constexpr bool CheckedSubImpl(T x, T y, T* result) {
90   static_assert(std::is_integral_v<T>, "Type must be integral");
91   // Since the value of x+y is undefined if we have a signed type, we compute
92   // it using the unsigned type of the same size.
93   using UnsignedDst = typename std::make_unsigned<T>::type;
94   using SignedDst = typename std::make_signed<T>::type;
95   const UnsignedDst ux = static_cast<UnsignedDst>(x);
96   const UnsignedDst uy = static_cast<UnsignedDst>(y);
97   const UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
98   // Subtraction is valid if either x and y have same sign, or (x-y) and x have
99   // the same sign.
100   if (std::is_signed_v<T>
101           ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) < 0
102           : x < y) {
103     return false;
104   }
105   *result = static_cast<T>(uresult);
106   return true;
107 }
108 
109 template <typename T, typename U, class Enable = void>
110 struct CheckedSubOp {};
111 
112 template <typename T, typename U>
113 struct CheckedSubOp<T,
114                     U,
115                     typename std::enable_if<std::is_integral_v<T> &&
116                                             std::is_integral_v<U>>::type> {
117   using result_type = typename MaxExponentPromotion<T, U>::type;
118   template <typename V>
119   static constexpr bool Do(T x, U y, V* result) {
120     if constexpr (CheckedSubFastOp<T, U>::is_supported) {
121       return CheckedSubFastOp<T, U>::Do(x, y, result);
122     }
123 
124     // Double the underlying type up to a full machine word.
125     using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
126     using Promotion =
127         typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
128                                    IntegerBitsPlusSign<intptr_t>::value),
129                                   typename BigEnoughPromotion<T, U>::type,
130                                   FastPromotion>::type;
131     // Fail if either operand is out of range for the promoted type.
132     // TODO(jschuh): This could be made to work for a broader range of values.
133     if (PA_BASE_NUMERICS_UNLIKELY(
134             !IsValueInRangeForNumericType<Promotion>(x) ||
135             !IsValueInRangeForNumericType<Promotion>(y))) {
136       return false;
137     }
138 
139     Promotion presult = {};
140     bool is_valid = true;
141     if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
142       presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
143     } else {
144       is_valid = CheckedSubImpl(static_cast<Promotion>(x),
145                                 static_cast<Promotion>(y), &presult);
146     }
147     if (!is_valid || !IsValueInRangeForNumericType<V>(presult)) {
148       return false;
149     }
150     *result = static_cast<V>(presult);
151     return true;
152   }
153 };
154 
155 template <typename T>
156 constexpr bool CheckedMulImpl(T x, T y, T* result) {
157   static_assert(std::is_integral_v<T>, "Type must be integral");
158   // Since the value of x*y is potentially undefined if we have a signed type,
159   // we compute it using the unsigned type of the same size.
160   using UnsignedDst = typename std::make_unsigned<T>::type;
161   using SignedDst = typename std::make_signed<T>::type;
162   const UnsignedDst ux = SafeUnsignedAbs(x);
163   const UnsignedDst uy = SafeUnsignedAbs(y);
164   const UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
165   const bool is_negative =
166       std::is_signed_v<T> && static_cast<SignedDst>(x ^ y) < 0;
167   // We have a fast out for unsigned identity or zero on the second operand.
168   // After that it's an unsigned overflow check on the absolute value, with
169   // a +1 bound for a negative result.
170   if (uy > UnsignedDst(!std::is_signed_v<T> || is_negative) &&
171       ux > (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy) {
172     return false;
173   }
174   *result = static_cast<T>(is_negative ? 0 - uresult : uresult);
175   return true;
176 }
177 
178 template <typename T, typename U, class Enable = void>
179 struct CheckedMulOp {};
180 
181 template <typename T, typename U>
182 struct CheckedMulOp<T,
183                     U,
184                     typename std::enable_if<std::is_integral_v<T> &&
185                                             std::is_integral_v<U>>::type> {
186   using result_type = typename MaxExponentPromotion<T, U>::type;
187   template <typename V>
188   static constexpr bool Do(T x, U y, V* result) {
189     if constexpr (CheckedMulFastOp<T, U>::is_supported) {
190       return CheckedMulFastOp<T, U>::Do(x, y, result);
191     }
192 
193     using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
194     // Verify the destination type can hold the result (always true for 0).
195     if (PA_BASE_NUMERICS_UNLIKELY(
196             (!IsValueInRangeForNumericType<Promotion>(x) ||
197              !IsValueInRangeForNumericType<Promotion>(y)) &&
198             x && y)) {
199       return false;
200     }
201 
202     Promotion presult = {};
203     bool is_valid = true;
204     if (CheckedMulFastOp<Promotion, Promotion>::is_supported) {
205       // The fast op may be available with the promoted type.
206       is_valid = CheckedMulFastOp<Promotion, Promotion>::Do(
207           static_cast<Promotion>(x), static_cast<Promotion>(y), &presult);
208     } else if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
209       presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
210     } else {
211       is_valid = CheckedMulImpl(static_cast<Promotion>(x),
212                                 static_cast<Promotion>(y), &presult);
213     }
214     if (!is_valid || !IsValueInRangeForNumericType<V>(presult)) {
215       return false;
216     }
217     *result = static_cast<V>(presult);
218     return true;
219   }
220 };
221 
222 // Division just requires a check for a zero denominator or an invalid negation
223 // on signed min/-1.
224 template <typename T, typename U, class Enable = void>
225 struct CheckedDivOp {};
226 
227 template <typename T, typename U>
228 struct CheckedDivOp<T,
229                     U,
230                     typename std::enable_if<std::is_integral_v<T> &&
231                                             std::is_integral_v<U>>::type> {
232   using result_type = typename MaxExponentPromotion<T, U>::type;
233   template <typename V>
234   static constexpr bool Do(T x, U y, V* result) {
235     if (PA_BASE_NUMERICS_UNLIKELY(!y)) {
236       return false;
237     }
238 
239     // The overflow check can be compiled away if we don't have the exact
240     // combination of types needed to trigger this case.
241     using Promotion = typename BigEnoughPromotion<T, U>::type;
242     if (PA_BASE_NUMERICS_UNLIKELY(
243             (std::is_signed_v<T> && std::is_signed_v<U> &&
244              IsTypeInRangeForNumericType<T, Promotion>::value &&
245              static_cast<Promotion>(x) ==
246                  std::numeric_limits<Promotion>::lowest() &&
247              y == static_cast<U>(-1)))) {
248       return false;
249     }
250 
251     // This branch always compiles away if the above branch wasn't removed.
252     if (PA_BASE_NUMERICS_UNLIKELY(
253             (!IsValueInRangeForNumericType<Promotion>(x) ||
254              !IsValueInRangeForNumericType<Promotion>(y)) &&
255             x)) {
256       return false;
257     }
258 
259     const Promotion presult = Promotion(x) / Promotion(y);
260     if (!IsValueInRangeForNumericType<V>(presult)) {
261       return false;
262     }
263     *result = static_cast<V>(presult);
264     return true;
265   }
266 };
267 
268 template <typename T, typename U, class Enable = void>
269 struct CheckedModOp {};
270 
271 template <typename T, typename U>
272 struct CheckedModOp<T,
273                     U,
274                     typename std::enable_if<std::is_integral_v<T> &&
275                                             std::is_integral_v<U>>::type> {
276   using result_type = typename MaxExponentPromotion<T, U>::type;
277   template <typename V>
278   static constexpr bool Do(T x, U y, V* result) {
279     if (PA_BASE_NUMERICS_UNLIKELY(!y)) {
280       return false;
281     }
282 
283     using Promotion = typename BigEnoughPromotion<T, U>::type;
284     if (PA_BASE_NUMERICS_UNLIKELY(
285             (std::is_signed_v<T> && std::is_signed_v<U> &&
286              IsTypeInRangeForNumericType<T, Promotion>::value &&
287              static_cast<Promotion>(x) ==
288                  std::numeric_limits<Promotion>::lowest() &&
289              y == static_cast<U>(-1)))) {
290       *result = 0;
291       return true;
292     }
293 
294     const Promotion presult =
295         static_cast<Promotion>(x) % static_cast<Promotion>(y);
296     if (!IsValueInRangeForNumericType<V>(presult)) {
297       return false;
298     }
299     *result = static_cast<Promotion>(presult);
300     return true;
301   }
302 };
303 
304 template <typename T, typename U, class Enable = void>
305 struct CheckedLshOp {};
306 
307 // Left shift. Shifts less than 0 or greater than or equal to the number
308 // of bits in the promoted type are undefined. Shifts of negative values
309 // are undefined. Otherwise it is defined when the result fits.
310 template <typename T, typename U>
311 struct CheckedLshOp<T,
312                     U,
313                     typename std::enable_if<std::is_integral_v<T> &&
314                                             std::is_integral_v<U>>::type> {
315   using result_type = T;
316   template <typename V>
317   static constexpr bool Do(T x, U shift, V* result) {
318     // Disallow negative numbers and verify the shift is in bounds.
319     if (PA_BASE_NUMERICS_LIKELY(
320             !IsValueNegative(x) &&
321             as_unsigned(shift) < as_unsigned(std::numeric_limits<T>::digits))) {
322       // Shift as unsigned to avoid undefined behavior.
323       *result = static_cast<V>(as_unsigned(x) << shift);
324       // If the shift can be reversed, we know it was valid.
325       return *result >> shift == x;
326     }
327 
328     // Handle the legal corner-case of a full-width signed shift of zero.
329     if (!std::is_signed_v<T> || x ||
330         as_unsigned(shift) != as_unsigned(std::numeric_limits<T>::digits)) {
331       return false;
332     }
333     *result = 0;
334     return true;
335   }
336 };
337 
338 template <typename T, typename U, class Enable = void>
339 struct CheckedRshOp {};
340 
341 // Right shift. Shifts less than 0 or greater than or equal to the number
342 // of bits in the promoted type are undefined. Otherwise, it is always defined,
343 // but a right shift of a negative value is implementation-dependent.
344 template <typename T, typename U>
345 struct CheckedRshOp<T,
346                     U,
347                     typename std::enable_if<std::is_integral_v<T> &&
348                                             std::is_integral_v<U>>::type> {
349   using result_type = T;
350   template <typename V>
351   static constexpr bool Do(T x, U shift, V* result) {
352     // Use sign conversion to push negative values out of range.
353     if (PA_BASE_NUMERICS_UNLIKELY(as_unsigned(shift) >=
354                                   IntegerBitsPlusSign<T>::value)) {
355       return false;
356     }
357 
358     const T tmp = x >> shift;
359     if (!IsValueInRangeForNumericType<V>(tmp)) {
360       return false;
361     }
362     *result = static_cast<V>(tmp);
363     return true;
364   }
365 };
366 
367 template <typename T, typename U, class Enable = void>
368 struct CheckedAndOp {};
369 
370 // For simplicity we support only unsigned integer results.
371 template <typename T, typename U>
372 struct CheckedAndOp<T,
373                     U,
374                     typename std::enable_if<std::is_integral_v<T> &&
375                                             std::is_integral_v<U>>::type> {
376   using result_type = typename std::make_unsigned<
377       typename MaxExponentPromotion<T, U>::type>::type;
378   template <typename V>
379   static constexpr bool Do(T x, U y, V* result) {
380     const result_type tmp =
381         static_cast<result_type>(x) & static_cast<result_type>(y);
382     if (!IsValueInRangeForNumericType<V>(tmp)) {
383       return false;
384     }
385     *result = static_cast<V>(tmp);
386     return true;
387   }
388 };
389 
390 template <typename T, typename U, class Enable = void>
391 struct CheckedOrOp {};
392 
393 // For simplicity we support only unsigned integers.
394 template <typename T, typename U>
395 struct CheckedOrOp<T,
396                    U,
397                    typename std::enable_if<std::is_integral_v<T> &&
398                                            std::is_integral_v<U>>::type> {
399   using result_type = typename std::make_unsigned<
400       typename MaxExponentPromotion<T, U>::type>::type;
401   template <typename V>
402   static constexpr bool Do(T x, U y, V* result) {
403     const result_type tmp =
404         static_cast<result_type>(x) | static_cast<result_type>(y);
405     if (!IsValueInRangeForNumericType<V>(tmp)) {
406       return false;
407     }
408     *result = static_cast<V>(tmp);
409     return true;
410   }
411 };
412 
413 template <typename T, typename U, class Enable = void>
414 struct CheckedXorOp {};
415 
416 // For simplicity we support only unsigned integers.
417 template <typename T, typename U>
418 struct CheckedXorOp<T,
419                     U,
420                     typename std::enable_if<std::is_integral_v<T> &&
421                                             std::is_integral_v<U>>::type> {
422   using result_type = typename std::make_unsigned<
423       typename MaxExponentPromotion<T, U>::type>::type;
424   template <typename V>
425   static constexpr bool Do(T x, U y, V* result) {
426     const result_type tmp =
427         static_cast<result_type>(x) ^ static_cast<result_type>(y);
428     if (!IsValueInRangeForNumericType<V>(tmp)) {
429       return false;
430     }
431     *result = static_cast<V>(tmp);
432     return true;
433   }
434 };
435 
436 // Max doesn't really need to be implemented this way because it can't fail,
437 // but it makes the code much cleaner to use the MathOp wrappers.
438 template <typename T, typename U, class Enable = void>
439 struct CheckedMaxOp {};
440 
441 template <typename T, typename U>
442 struct CheckedMaxOp<T,
443                     U,
444                     typename std::enable_if<std::is_arithmetic_v<T> &&
445                                             std::is_arithmetic_v<U>>::type> {
446   using result_type = typename MaxExponentPromotion<T, U>::type;
447   template <typename V>
448   static constexpr bool Do(T x, U y, V* result) {
449     const result_type tmp = IsGreater<T, U>::Test(x, y)
450                                 ? static_cast<result_type>(x)
451                                 : static_cast<result_type>(y);
452     if (!IsValueInRangeForNumericType<V>(tmp)) {
453       return false;
454     }
455     *result = static_cast<V>(tmp);
456     return true;
457   }
458 };
459 
460 // Min doesn't really need to be implemented this way because it can't fail,
461 // but it makes the code much cleaner to use the MathOp wrappers.
462 template <typename T, typename U, class Enable = void>
463 struct CheckedMinOp {};
464 
465 template <typename T, typename U>
466 struct CheckedMinOp<T,
467                     U,
468                     typename std::enable_if<std::is_arithmetic_v<T> &&
469                                             std::is_arithmetic_v<U>>::type> {
470   using result_type = typename LowestValuePromotion<T, U>::type;
471   template <typename V>
472   static constexpr bool Do(T x, U y, V* result) {
473     const result_type tmp = IsLess<T, U>::Test(x, y)
474                                 ? static_cast<result_type>(x)
475                                 : static_cast<result_type>(y);
476     if (!IsValueInRangeForNumericType<V>(tmp)) {
477       return false;
478     }
479     *result = static_cast<V>(tmp);
480     return true;
481   }
482 };
483 
484 // This is just boilerplate that wraps the standard floating point arithmetic.
485 // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
486 #define PA_BASE_FLOAT_ARITHMETIC_OPS(NAME, OP)                      \
487   template <typename T, typename U>                                 \
488   struct Checked##NAME##Op<                                         \
489       T, U,                                                         \
490       typename std::enable_if<std::is_floating_point_v<T> ||        \
491                               std::is_floating_point_v<U>>::type> { \
492     using result_type = typename MaxExponentPromotion<T, U>::type;  \
493     template <typename V>                                           \
494     static constexpr bool Do(T x, U y, V* result) {                 \
495       using Promotion = typename MaxExponentPromotion<T, U>::type;  \
496       const Promotion presult = x OP y;                             \
497       if (!IsValueInRangeForNumericType<V>(presult))                \
498         return false;                                               \
499       *result = static_cast<V>(presult);                            \
500       return true;                                                  \
501     }                                                               \
502   };
503 
504 PA_BASE_FLOAT_ARITHMETIC_OPS(Add, +)
505 PA_BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
506 PA_BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
507 PA_BASE_FLOAT_ARITHMETIC_OPS(Div, /)
508 
509 #undef PA_BASE_FLOAT_ARITHMETIC_OPS
510 
511 // Floats carry around their validity state with them, but integers do not. So,
512 // we wrap the underlying value in a specialization in order to hide that detail
513 // and expose an interface via accessors.
514 enum NumericRepresentation {
515   NUMERIC_INTEGER,
516   NUMERIC_FLOATING,
517   NUMERIC_UNKNOWN
518 };
519 
520 template <typename NumericType>
521 struct GetNumericRepresentation {
522   static const NumericRepresentation value =
523       std::is_integral_v<NumericType>
524           ? NUMERIC_INTEGER
525           : (std::is_floating_point_v<NumericType> ? NUMERIC_FLOATING
526                                                    : NUMERIC_UNKNOWN);
527 };
528 
529 template <typename T,
530           NumericRepresentation type = GetNumericRepresentation<T>::value>
531 class CheckedNumericState {};
532 
533 // Integrals require quite a bit of additional housekeeping to manage state.
534 template <typename T>
535 class CheckedNumericState<T, NUMERIC_INTEGER> {
536  public:
537   template <typename Src = int>
538   constexpr explicit CheckedNumericState(Src value = 0, bool is_valid = true)
539       : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
540         value_(WellDefinedConversionOrZero(value, is_valid_)) {
541     static_assert(std::is_arithmetic_v<Src>, "Argument must be numeric.");
542   }
543 
544   template <typename Src>
545   constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
546       : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
547 
548   constexpr bool is_valid() const { return is_valid_; }
549 
550   constexpr T value() const { return value_; }
551 
552  private:
553   // Ensures that a type conversion does not trigger undefined behavior.
554   template <typename Src>
555   static constexpr T WellDefinedConversionOrZero(Src value, bool is_valid) {
556     using SrcType = typename internal::UnderlyingType<Src>::type;
557     return (std::is_integral_v<SrcType> || is_valid) ? static_cast<T>(value)
558                                                      : 0;
559   }
560 
561   // is_valid_ precedes value_ because member initializers in the constructors
562   // are evaluated in field order, and is_valid_ must be read when initializing
563   // value_.
564   bool is_valid_;
565   T value_;
566 };
567 
568 // Floating points maintain their own validity, but need translation wrappers.
569 template <typename T>
570 class CheckedNumericState<T, NUMERIC_FLOATING> {
571  public:
572   template <typename Src = double>
573   constexpr explicit CheckedNumericState(Src value = 0.0, bool is_valid = true)
574       : value_(WellDefinedConversionOrNaN(
575             value,
576             is_valid && IsValueInRangeForNumericType<T>(value))) {}
577 
578   template <typename Src>
579   constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
580       : CheckedNumericState(rhs.value(), rhs.is_valid()) {}
581 
582   constexpr bool is_valid() const {
583     // Written this way because std::isfinite is not reliably constexpr.
584     return PA_IsConstantEvaluated()
585                ? value_ <= std::numeric_limits<T>::max() &&
586                      value_ >= std::numeric_limits<T>::lowest()
587                : std::isfinite(value_);
588   }
589 
590   constexpr T value() const { return value_; }
591 
592  private:
593   // Ensures that a type conversion does not trigger undefined behavior.
594   template <typename Src>
595   static constexpr T WellDefinedConversionOrNaN(Src value, bool is_valid) {
596     using SrcType = typename internal::UnderlyingType<Src>::type;
597     return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
598                 NUMERIC_RANGE_CONTAINED ||
599             is_valid)
600                ? static_cast<T>(value)
601                : std::numeric_limits<T>::quiet_NaN();
602   }
603 
604   T value_;
605 };
606 
607 }  // namespace partition_alloc::internal::base::internal
608 
609 #endif  // PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_CHECKED_MATH_IMPL_H_
610