Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / include / o3tl / safeint.hxx
bloba32c6beea142081b31127a1f841c893388bcc0bb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #pragma once
12 #include <sal/config.h>
14 #include <algorithm>
15 #include <cassert>
16 #include <limits>
17 #include <type_traits>
19 #if defined(_MSC_VER)
20 #include <safeint.h>
21 #else
22 #ifndef __has_builtin
23 # define __has_builtin(x) 0
24 #endif
25 #endif
27 namespace o3tl
30 template <typename T> inline constexpr T saturating_add(T a, T b)
32 if (b >= 0) {
33 if (a <= std::numeric_limits<T>::max() - b) {
34 return a + b;
35 } else {
36 return std::numeric_limits<T>::max();
38 } else {
39 if (a >= std::numeric_limits<T>::min() - b) {
40 return a + b;
41 } else {
42 return std::numeric_limits<T>::min();
47 template <typename T> inline constexpr T saturating_sub(T a, T b)
49 if (b >= 0) {
50 if (a >= std::numeric_limits<T>::min() + b) {
51 return a - b;
52 } else {
53 return std::numeric_limits<T>::min();
55 } else {
56 if (a <= std::numeric_limits<T>::max() + b) {
57 return a - b;
58 } else {
59 return std::numeric_limits<T>::max();
64 template<typename T> inline
65 typename std::enable_if<std::is_signed<T>::value, T>::type saturating_toggle_sign(
66 T a)
68 if (a == std::numeric_limits<T>::min())
69 return std::numeric_limits<T>::max();
70 return a * -1;
73 #if defined(_MSC_VER)
75 template<typename T> inline bool checked_multiply(T a, T b, T& result)
77 return !msl::utilities::SafeMultiply(a, b, result);
80 template<typename T> inline bool checked_add(T a, T b, T& result)
82 return !msl::utilities::SafeAdd(a, b, result);
85 template<typename T> inline bool checked_sub(T a, T b, T& result)
87 return !msl::utilities::SafeSubtract(a, b, result);
90 #elif (defined __GNUC__ && !defined __clang__) || (__has_builtin(__builtin_mul_overflow) && !(defined ANDROID && defined __clang__) && !(defined(__clang__) && (defined(__arm__) || defined(__i386__))))
91 // 32-bit clang fails with undefined reference to `__mulodi4'
93 template<typename T> inline bool checked_multiply(T a, T b, T& result)
95 return __builtin_mul_overflow(a, b, &result);
98 template<typename T> inline bool checked_add(T a, T b, T& result)
100 return __builtin_add_overflow(a, b, &result);
103 template<typename T> inline bool checked_sub(T a, T b, T& result)
105 return __builtin_sub_overflow(a, b, &result);
108 #else
110 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
111 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_multiply(T a, T b, T& result)
113 if (a > 0) { /* a is positive */
114 if (b > 0) { /* a and b are positive */
115 if (a > (std::numeric_limits<T>::max() / b)) {
116 return true; /* Handle error */
118 } else { /* a positive, b nonpositive */
119 if (b < (std::numeric_limits<T>::min() / a)) {
120 return true; /* Handle error */
122 } /* a positive, b nonpositive */
123 } else { /* a is nonpositive */
124 if (b > 0) { /* a is nonpositive, b is positive */
125 if (a < (std::numeric_limits<T>::min() / b)) {
126 return true; /* Handle error */
128 } else { /* a and b are nonpositive */
129 if ( (a != 0) && (b < (std::numeric_limits<T>::max() / a))) {
130 return true; /* Handle error */
132 } /* End if a and b are nonpositive */
133 } /* End if a is nonpositive */
135 result = a * b;
137 return false;
140 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
141 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_multiply(T a, T b, T& result)
143 if (b && a > std::numeric_limits<T>::max() / b) {
144 return true;/* Handle error */
147 result = a * b;
149 return false;
152 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
153 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_add(T a, T b, T& result)
155 if (((b > 0) && (a > (std::numeric_limits<T>::max() - b))) ||
156 ((b < 0) && (a < (std::numeric_limits<T>::min() - b)))) {
157 return true;
160 result = a + b;
162 return false;
165 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
166 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_add(T a, T b, T& result)
168 if (std::numeric_limits<T>::max() - a < b) {
169 return true;/* Handle error */
172 result = a + b;
174 return false;
177 //https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
178 template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_sub(T a, T b, T& result)
180 if ((b > 0 && a < std::numeric_limits<T>::min() + b) ||
181 (b < 0 && a > std::numeric_limits<T>::max() + b)) {
182 return true;
185 result = a - b;
187 return false;
190 //https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
191 template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_sub(T a, T b, T& result)
193 if (a < b) {
194 return true;
197 result = a - b;
199 return false;
202 #endif
204 template<typename T> constexpr std::enable_if_t<std::is_signed_v<T>, std::make_unsigned_t<T>>
205 make_unsigned(T value)
207 assert(value >= 0);
208 return value;
211 template<typename T1, typename T2> constexpr std::enable_if_t<std::is_unsigned_v<T1>, T1>
212 clamp_to_unsigned(T2 value) {
213 if constexpr (std::is_unsigned_v<T2>) {
214 // coverity[result_independent_of_operands] - suppress warning for template
215 return value <= std::numeric_limits<T1>::max() ? value : std::numeric_limits<T1>::max();
216 } else {
217 static_assert(std::is_signed_v<T2>);
218 return value < 0 ? 0 : clamp_to_unsigned<T1>(make_unsigned(value));
222 // An implicit conversion from T2 to T1, useful in places where an explicit conversion from T2 to
223 // T1 is needed (e.g., in list initialization, if the implicit conversion would be narrowing) but
224 // tools like -fsanitize=implicit-conversion should still be able to detect truncation:
225 template<typename T1, typename T2> constexpr T1 narrowing(T2 value) { return value; }
227 // std::min wrapped to inform coverity that the result is now deemed sanitized
228 // coverity[ -taint_source ]
229 template<typename T> [[nodiscard]] inline T sanitizing_min(T a, T b)
231 return std::min(a, b);
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */