Exiv2
safe_op.hpp
1// ***************************************************************** -*- C++ -*-
2/*
3 * Copyright (C) 2004-2021 Exiv2 authors
4 * This program is part of the Exiv2 distribution.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef SAFE_OP_HPP_
22#define SAFE_OP_HPP_
23
24#include <limits>
25#include <stdexcept>
26
27#ifdef _MSC_VER
28#include <Intsafe.h>
29#endif
30
34namespace Safe
35{
58 namespace Internal
59 {
67 template <typename T>
68 struct is_signed
69 {
70 enum
71 {
72 VALUE = T(-1) < T(0)
73 };
74 };
75
82 template <bool B, class T = void>
83 struct enable_if
84 {
85 };
86
90 template <class T>
91 struct enable_if<true, T>
92 {
93 typedef T type;
94 };
95
113 template <typename T>
114 typename enable_if<is_signed<T>::VALUE && sizeof(T) >= sizeof(int), bool>::type fallback_add_overflow(
115 T summand_1, T summand_2, T& result)
116 {
117 if (((summand_2 >= 0) && (summand_1 > std::numeric_limits<T>::max() - summand_2)) ||
118 ((summand_2 < 0) && (summand_1 < std::numeric_limits<T>::min() - summand_2))) {
119 return true;
120 } else {
121 result = summand_1 + summand_2;
122 return false;
123 }
124 }
125
145 template <typename T>
146 typename enable_if<is_signed<T>::VALUE && sizeof(T) < sizeof(int), bool>::type fallback_add_overflow(
147 T summand_1, T summand_2, T& result)
148 {
149 const int res = summand_1 + summand_2;
150 if ((res > std::numeric_limits<T>::max()) || (res < std::numeric_limits<T>::min())) {
151 return true;
152 } else {
153 result = static_cast<T>(res);
154 return false;
155 }
156 }
157
174 template <typename T>
175 typename enable_if<!is_signed<T>::VALUE, bool>::type fallback_add_overflow(T summand_1, T summand_2, T& result)
176 {
177 result = summand_1 + summand_2;
178 return result < summand_1;
179 }
180
194 template <typename T>
195 bool builtin_add_overflow(T summand_1, T summand_2, T& result)
196 {
197 return fallback_add_overflow(summand_1, summand_2, result);
198 }
199
200#if defined(__GNUC__) || defined(__clang__)
201#if __GNUC__ >= 5 || __clang_major__ >= 3
202
213#define SPECIALIZE_builtin_add_overflow(type, builtin_name) \
214 /* Full specialization of builtin_add_overflow for type using the */ \
215 /* builtin_name intrinsic */ \
216 template <> \
217 inline bool builtin_add_overflow<type>(type summand_1, type summand_2, type & result) \
218 { \
219 return builtin_name(summand_1, summand_2, &result); \
220 }
221
222 SPECIALIZE_builtin_add_overflow(int, __builtin_sadd_overflow);
223 SPECIALIZE_builtin_add_overflow(long, __builtin_saddl_overflow);
224 SPECIALIZE_builtin_add_overflow(long long, __builtin_saddll_overflow);
225
226 SPECIALIZE_builtin_add_overflow(unsigned int, __builtin_uadd_overflow);
227 SPECIALIZE_builtin_add_overflow(unsigned long, __builtin_uaddl_overflow);
228 SPECIALIZE_builtin_add_overflow(unsigned long long, __builtin_uaddll_overflow);
229
230#undef SPECIALIZE_builtin_add_overflow
231#endif // __GNUC__ >= 5 || __clang_major >= 3
232
233#elif defined(_MSC_VER)
234// intrinsics are not in available in MSVC 2005 and earlier
235#if _MSC_VER >= 1400
236
250#define SPECIALIZE_builtin_add_overflow_WIN(type, builtin_name) \
251 template <> \
252 inline bool builtin_add_overflow(type summand_1, type summand_2, type& result) \
253 { \
254 return builtin_name(summand_1, summand_2, &result) != S_OK; \
255 }
256
257 SPECIALIZE_builtin_add_overflow_WIN(unsigned int, UIntAdd);
258 SPECIALIZE_builtin_add_overflow_WIN(unsigned long, ULongAdd);
259 SPECIALIZE_builtin_add_overflow_WIN(unsigned long long, ULongLongAdd);
260
261#undef SPECIALIZE_builtin_add_overflow_WIN
262
263#endif // _MSC_VER >= 1400
264#endif // defined(_MSC_VER)
265
266 } // namespace Internal
267
287 template <typename T>
288 T add(T summand_1, T summand_2)
289 {
290 T res = 0;
291 if (Internal::builtin_add_overflow(summand_1, summand_2, res)) {
292 throw std::overflow_error("Overflow in addition");
293 }
294 return res;
295 }
296
319 template <typename T>
321 {
322 if (num == std::numeric_limits<T>::min()) {
323 return std::numeric_limits<T>::max();
324 }
325 return num < 0 ? -num : num;
326 }
327
328} // namespace Safe
329
330#endif // SAFE_OP_HPP_
Arithmetic operations with overflow checks.
Definition: safe_op.hpp:35
T add(T summand_1, T summand_2)
Safe addition, throws an exception on overflow.
Definition: safe_op.hpp:288
Internal::enable_if< Internal::is_signed< T >::VALUE, T >::type abs(T num)
Calculates the absolute value of a number without producing negative values.
Definition: safe_op.hpp:320
Helper struct for SFINAE, from C++11.
Definition: safe_op.hpp:84
Helper struct to determine whether a type is signed or unsigned.
Definition: safe_op.hpp:69