LibreOffice Module o3tl (master) 1
safeint.hxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10#pragma once
11
12#include <sal/config.h>
13
14#include <algorithm>
15#include <cassert>
16#include <limits>
17#include <type_traits>
18
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
26
27namespace o3tl
28{
29
30template <typename T> inline constexpr T saturating_add(T a, T b)
31{
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();
37 }
38 } else {
39 if (a >= std::numeric_limits<T>::min() - b) {
40 return a + b;
41 } else {
42 return std::numeric_limits<T>::min();
43 }
44 }
45}
46
47template <typename T> inline constexpr T saturating_sub(T a, T b)
48{
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();
54 }
55 } else {
56 if (a <= std::numeric_limits<T>::max() + b) {
57 return a - b;
58 } else {
59 return std::numeric_limits<T>::max();
60 }
61 }
62}
63
64template<typename T> inline
65typename std::enable_if<std::is_signed<T>::value, T>::type saturating_toggle_sign(
66 T a)
67{
68 if (a == std::numeric_limits<T>::min())
69 return std::numeric_limits<T>::max();
70 return a * -1;
71}
72
73#if defined(_MSC_VER)
74
75template<typename T> inline bool checked_multiply(T a, T b, T& result)
76{
77 return !msl::utilities::SafeMultiply(a, b, result);
78}
79
80template<typename T> inline bool checked_add(T a, T b, T& result)
81{
82 return !msl::utilities::SafeAdd(a, b, result);
83}
84
85template<typename T> inline bool checked_sub(T a, T b, T& result)
86{
87 return !msl::utilities::SafeSubtract(a, b, result);
88}
89
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'
92
93template<typename T> inline bool checked_multiply(T a, T b, T& result)
94{
95 return __builtin_mul_overflow(a, b, &result);
96}
97
98template<typename T> inline bool checked_add(T a, T b, T& result)
99{
100 return __builtin_add_overflow(a, b, &result);
101}
102
103template<typename T> inline bool checked_sub(T a, T b, T& result)
104{
105 return __builtin_sub_overflow(a, b, &result);
106}
107
108#else
109
110//https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
111template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_multiply(T a, T b, T& result)
112{
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 */
117 }
118 } else { /* a positive, b nonpositive */
119 if (b < (std::numeric_limits<T>::min() / a)) {
120 return true; /* Handle error */
121 }
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 */
127 }
128 } else { /* a and b are nonpositive */
129 if ( (a != 0) && (b < (std::numeric_limits<T>::max() / a))) {
130 return true; /* Handle error */
131 }
132 } /* End if a and b are nonpositive */
133 } /* End if a is nonpositive */
134
135 result = a * b;
136
137 return false;
138}
139
140//https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
141template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_multiply(T a, T b, T& result)
142{
143 if (b && a > std::numeric_limits<T>::max() / b) {
144 return true;/* Handle error */
145 }
146
147 result = a * b;
148
149 return false;
150}
151
152//https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
153template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_add(T a, T b, T& result)
154{
155 if (((b > 0) && (a > (std::numeric_limits<T>::max() - b))) ||
156 ((b < 0) && (a < (std::numeric_limits<T>::min() - b)))) {
157 return true;
158 }
159
160 result = a + b;
161
162 return false;
163}
164
165//https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
166template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_add(T a, T b, T& result)
167{
168 if (std::numeric_limits<T>::max() - a < b) {
169 return true;/* Handle error */
170 }
171
172 result = a + b;
173
174 return false;
175}
176
177//https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
178template<typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type checked_sub(T a, T b, T& result)
179{
180 if ((b > 0 && a < std::numeric_limits<T>::min() + b) ||
181 (b < 0 && a > std::numeric_limits<T>::max() + b)) {
182 return true;
183 }
184
185 result = a - b;
186
187 return false;
188}
189
190//https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
191template<typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type checked_sub(T a, T b, T& result)
192{
193 if (a < b) {
194 return true;
195 }
196
197 result = a - b;
198
199 return false;
200}
201
202#endif
203
204template<typename T> constexpr std::enable_if_t<std::is_signed_v<T>, std::make_unsigned_t<T>>
206{
207 assert(value >= 0);
208 return value;
209}
210
211template<typename T1, typename T2> constexpr std::enable_if_t<std::is_unsigned_v<T1>, T1>
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));
219 }
220}
221
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:
225template<typename T1, typename T2> constexpr T1 narrowing(T2 value) { return value; }
226
227// std::min wrapped to inform coverity that the result is now deemed sanitized
228// coverity[ -taint_source ]
229template<typename T> [[nodiscard]] inline T sanitizing_min(T a, T b)
230{
231 return std::min(a, b);
232}
233
234}
235
236/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Any value
uno_Any a
std::enable_if< std::is_signed< T >::value, bool >::type checked_add(T a, T b, T &result)
Definition: safeint.hxx:153
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
Definition: safeint.hxx:205
constexpr T1 narrowing(T2 value)
Definition: safeint.hxx:225
std::enable_if< std::is_signed< T >::value, T >::type saturating_toggle_sign(T a)
Definition: safeint.hxx:65
T sanitizing_min(T a, T b)
Definition: safeint.hxx:229
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)
Definition: safeint.hxx:111
constexpr T saturating_add(T a, T b)
Definition: safeint.hxx:30
constexpr std::enable_if_t< std::is_unsigned_v< T1 >, T1 > clamp_to_unsigned(T2 value)
Definition: safeint.hxx:212
constexpr T saturating_sub(T a, T b)
Definition: safeint.hxx:47
std::enable_if< std::is_signed< T >::value, bool >::type checked_sub(T a, T b, T &result)
Definition: safeint.hxx:178
Any result