1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
12 #include <sal/config.h>
17 #include <type_traits>
23 # define __has_builtin(x) 0
30 template <typename T
> inline constexpr T
saturating_add(T a
, T b
)
33 if (a
<= std::numeric_limits
<T
>::max() - b
) {
36 return std::numeric_limits
<T
>::max();
39 if (a
>= std::numeric_limits
<T
>::min() - b
) {
42 return std::numeric_limits
<T
>::min();
47 template <typename T
> inline constexpr T
saturating_sub(T a
, T b
)
50 if (a
>= std::numeric_limits
<T
>::min() + b
) {
53 return std::numeric_limits
<T
>::min();
56 if (a
<= std::numeric_limits
<T
>::max() + b
) {
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(
68 if (a
== std::numeric_limits
<T
>::min())
69 return std::numeric_limits
<T
>::max();
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
);
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 */
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 */
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
)))) {
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 */
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
)) {
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
)
204 template<typename T
> constexpr std::enable_if_t
<std::is_signed_v
<T
>, std::make_unsigned_t
<T
>>
205 make_unsigned(T 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();
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: */