• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <cassert>
12 #include <climits>
13 #include <cmath>
14 #include <cstdlib>
15 #include <limits>
16 #include <type_traits>
17 
18 #include "build/build_config.h"
19 #include "partition_alloc/partition_alloc_base/numerics/safe_conversions.h"
20 
21 #if BUILDFLAG(IS_ASMJS)
22 // Optimized safe math instructions are incompatible with asmjs.
23 #define PA_BASE_HAS_OPTIMIZED_SAFE_MATH (0)
24 // Where available use builtin math overflow support on Clang and GCC.
25 #elif !defined(__native_client__) &&                       \
26     ((defined(__clang__) &&                                \
27       ((__clang_major__ > 3) ||                            \
28        (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
29      (defined(__GNUC__) && __GNUC__ >= 5))
30 #include "partition_alloc/partition_alloc_base/numerics/safe_math_clang_gcc_impl.h"
31 #define PA_BASE_HAS_OPTIMIZED_SAFE_MATH (1)
32 #else
33 #define PA_BASE_HAS_OPTIMIZED_SAFE_MATH (0)
34 #endif
35 
36 namespace partition_alloc::internal::base::internal {
37 
38 // These are the non-functioning boilerplate implementations of the optimized
39 // safe math routines.
40 #if !PA_BASE_HAS_OPTIMIZED_SAFE_MATH
41 template <typename T, typename U>
42 struct CheckedAddFastOp {
43   static const bool is_supported = false;
44   template <typename V>
DoCheckedAddFastOp45   static constexpr bool Do(T, U, V*) {
46     // Force a compile failure if instantiated.
47     return CheckOnFailure::template HandleFailure<bool>();
48   }
49 };
50 
51 template <typename T, typename U>
52 struct CheckedSubFastOp {
53   static const bool is_supported = false;
54   template <typename V>
DoCheckedSubFastOp55   static constexpr bool Do(T, U, V*) {
56     // Force a compile failure if instantiated.
57     return CheckOnFailure::template HandleFailure<bool>();
58   }
59 };
60 
61 template <typename T, typename U>
62 struct CheckedMulFastOp {
63   static const bool is_supported = false;
64   template <typename V>
DoCheckedMulFastOp65   static constexpr bool Do(T, U, V*) {
66     // Force a compile failure if instantiated.
67     return CheckOnFailure::template HandleFailure<bool>();
68   }
69 };
70 
71 template <typename T, typename U>
72 struct ClampedAddFastOp {
73   static const bool is_supported = false;
74   template <typename V>
DoClampedAddFastOp75   static constexpr V Do(T, U) {
76     // Force a compile failure if instantiated.
77     return CheckOnFailure::template HandleFailure<V>();
78   }
79 };
80 
81 template <typename T, typename U>
82 struct ClampedSubFastOp {
83   static const bool is_supported = false;
84   template <typename V>
DoClampedSubFastOp85   static constexpr V Do(T, U) {
86     // Force a compile failure if instantiated.
87     return CheckOnFailure::template HandleFailure<V>();
88   }
89 };
90 
91 template <typename T, typename U>
92 struct ClampedMulFastOp {
93   static const bool is_supported = false;
94   template <typename V>
DoClampedMulFastOp95   static constexpr V Do(T, U) {
96     // Force a compile failure if instantiated.
97     return CheckOnFailure::template HandleFailure<V>();
98   }
99 };
100 
101 template <typename T>
102 struct ClampedNegFastOp {
103   static const bool is_supported = false;
DoClampedNegFastOp104   static constexpr T Do(T) {
105     // Force a compile failure if instantiated.
106     return CheckOnFailure::template HandleFailure<T>();
107   }
108 };
109 #endif  // PA_BASE_HAS_OPTIMIZED_SAFE_MATH
110 #undef PA_BASE_HAS_OPTIMIZED_SAFE_MATH
111 
112 // This is used for UnsignedAbs, where we need to support floating-point
113 // template instantiations even though we don't actually support the operations.
114 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
115 // so the float versions will not compile.
116 template <typename Numeric,
117           bool IsInteger = std::is_integral_v<Numeric>,
118           bool IsFloat = std::is_floating_point_v<Numeric>>
119 struct UnsignedOrFloatForSize;
120 
121 template <typename Numeric>
122 struct UnsignedOrFloatForSize<Numeric, true, false> {
123   using type = typename std::make_unsigned<Numeric>::type;
124 };
125 
126 template <typename Numeric>
127 struct UnsignedOrFloatForSize<Numeric, false, true> {
128   using type = Numeric;
129 };
130 
131 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
132 // floating points. These don't perform any overflow checking. Rather, they
133 // exhibit well-defined overflow semantics and rely on the caller to detect
134 // if an overflow occurred.
135 
136 template <typename T,
137           typename std::enable_if<std::is_integral_v<T>>::type* = nullptr>
138 constexpr T NegateWrapper(T value) {
139   using UnsignedT = typename std::make_unsigned<T>::type;
140   // This will compile to a NEG on Intel, and is normal negation on ARM.
141   return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
142 }
143 
144 template <typename T,
145           typename std::enable_if<std::is_floating_point_v<T>>::type* = nullptr>
146 constexpr T NegateWrapper(T value) {
147   return -value;
148 }
149 
150 template <typename T,
151           typename std::enable_if<std::is_integral_v<T>>::type* = nullptr>
152 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
153   return ~value;
154 }
155 
156 template <typename T,
157           typename std::enable_if<std::is_integral_v<T>>::type* = nullptr>
158 constexpr T AbsWrapper(T value) {
159   return static_cast<T>(SafeUnsignedAbs(value));
160 }
161 
162 template <typename T,
163           typename std::enable_if<std::is_floating_point_v<T>>::type* = nullptr>
164 constexpr T AbsWrapper(T value) {
165   return value < 0 ? -value : value;
166 }
167 
168 template <template <typename, typename, typename> class M,
169           typename L,
170           typename R>
171 struct MathWrapper {
172   using math = M<typename UnderlyingType<L>::type,
173                  typename UnderlyingType<R>::type,
174                  void>;
175   using type = typename math::result_type;
176 };
177 
178 // The following macros are just boilerplate for the standard arithmetic
179 // operator overloads and variadic function templates. A macro isn't the nicest
180 // solution, but it beats rewriting these over and over again.
181 #define PA_BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)    \
182   template <typename L, typename R, typename... Args>                   \
183   constexpr auto CL_ABBR##OP_NAME(const L lhs, const R rhs,             \
184                                   const Args... args) {                 \
185     return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
186                                                               args...); \
187   }
188 
189 #define PA_BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP,  \
190                                              CMP_OP)                       \
191   /* Binary arithmetic operator for all CLASS##Numeric operations. */      \
192   template <typename L, typename R,                                        \
193             typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* =   \
194                 nullptr>                                                   \
195   constexpr CLASS##Numeric<                                                \
196       typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type>                \
197   operator OP(const L lhs, const R rhs) {                                  \
198     return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs,  \
199                                                                      rhs); \
200   }                                                                        \
201   /* Assignment arithmetic operator implementation from CLASS##Numeric. */ \
202   template <typename L>                                                    \
203   template <typename R>                                                    \
204   constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(         \
205       const R rhs) {                                                       \
206     return MathOp<CLASS##OP_NAME##Op>(rhs);                                \
207   }                                                                        \
208   /* Variadic arithmetic functions that return CLASS##Numeric. */          \
209   PA_BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
210 
211 }  // namespace partition_alloc::internal::base::internal
212 
213 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
214