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