Exiv2
safe_op.hpp
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #ifndef SAFE_OP_HPP_
4 #define SAFE_OP_HPP_
5 
6 #include <limits>
7 #include <stdexcept>
8 #include <type_traits>
9 
10 #ifdef _MSC_VER
11 #include <Intsafe.h>
12 #endif
13 
17 namespace Safe {
40 namespace Internal {
61 template <typename T>
62 bool fallback_add_overflow(T summand_1, T summand_2, T& result) {
63  if constexpr (std::is_signed_v<T> && sizeof(T) >= sizeof(int)) {
64  if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
65  ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2)))
66  return true;
67  result = summand_1 + summand_2;
68  return false;
69  } else if constexpr (std::is_signed_v<T> && sizeof(T) < sizeof(int)) {
70  const int res = summand_1 + summand_2;
71  if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
72  return true;
73  }
74  result = static_cast<T>(res);
75  return false;
76  } else {
77  result = summand_1 + summand_2;
78  return result < summand_1;
79  }
80 }
81 
95 template <typename T>
96 bool builtin_add_overflow(T summand_1, T summand_2, T& result) {
97  return fallback_add_overflow(summand_1, summand_2, result);
98 }
99 
100 #if defined(__GNUC__) || defined(__clang__)
101 #if __GNUC__ >= 5 || __clang_major__ >= 3
102 
113 #define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
114  /* Full specialization of builtin_add_overflow for type using the */ \
115  /* builtin_name intrinsic */ \
116  template <> \
117  inline bool builtin_add_overflow<type>(type summand_1, type summand_2, type & result) { \
118  return builtin_name(summand_1, summand_2, &result); \
119  }
120 
121 SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
122 SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
123 SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
124 
125 SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
126 SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
127 SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
128 
129 #undef SPECIALIZE_builtin_add_overflow
130 #endif // __GNUC__ >= 5 || __clang_major >= 3
131 
132 #endif
133 
134 } // namespace Internal
135 
156 template <typename T>
157 T add(T summand_1, T summand_2) {
158  T res = 0;
159  if (Internal::builtin_add_overflow(summand_1, summand_2, res)) {
160  throw std::overflow_error("Overflow in addition");
161  }
162  return res;
163 }
164 
187 template <typename T>
188 T abs(T num) noexcept {
189  if constexpr (std::is_signed_v<T>) {
190  if (num == std::numeric_limits<T>::min())
191  return std::numeric_limits<T>::max();
192  return num < 0 ? -num : num;
193  }
194  return num;
195 }
196 
197 } // namespace Safe
198 
199 #endif // SAFE_OP_HPP_
bool fallback_add_overflow(T summand_1, T summand_2, T &result)
Check the addition of two numbers for overflows for signed integer types larger than int or with the ...
Definition: safe_op.hpp:62
Arithmetic operations with overflow checks.
Definition: safe_op.hpp:17
T add(T summand_1, T summand_2)
Safe addition, throws an exception on overflow.
Definition: safe_op.hpp:157
T abs(T num) noexcept
Calculates the absolute value of a number without producing negative values.
Definition: safe_op.hpp:188
bool builtin_add_overflow(T summand_1, T summand_2, T &result)
Overflow addition check using compiler intrinsics.
Definition: safe_op.hpp:96