Line data Source code
1 : /**********************************************************************
2 : *
3 : * Name: cpl_safemaths.hpp
4 : * Project: CPL - Common Portability Library
5 : * Purpose: Arithmetic overflow checking
6 : * Author: Even Rouault <even.rouault at spatialys.com>
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #ifndef CPL_SAFEMATHS_INCLUDED
15 : #define CPL_SAFEMATHS_INCLUDED
16 :
17 : #include <exception>
18 : #include <limits>
19 :
20 : #include <cstdint>
21 :
22 : #ifndef __has_builtin
23 : #define __has_builtin(x) 0
24 : #endif
25 :
26 : #if (__GNUC__ >= 5 && !defined(__INTEL_COMPILER)) || \
27 : __has_builtin(__builtin_sadd_overflow)
28 : #define BUILTIN_OVERFLOW_CHECK_AVAILABLE
29 :
30 : #elif defined(_MSC_VER)
31 :
32 : #include "safeint.h"
33 :
34 : #endif
35 :
36 : #if defined(__clang__)
37 : #pragma clang diagnostic push
38 : #pragma clang diagnostic ignored "-Wweak-vtables"
39 : #endif
40 :
41 : template <typename T> struct CPLSafeInt
42 : {
43 : const T val;
44 :
45 90630 : inline explicit CPLSafeInt(T valIn) : val(valIn)
46 : {
47 90630 : }
48 :
49 90630 : inline T v() const
50 : {
51 90630 : return val;
52 : }
53 : };
54 :
55 : class CPLSafeIntOverflow : public std::exception
56 : {
57 : public:
58 36 : inline CPLSafeIntOverflow()
59 36 : {
60 36 : }
61 : };
62 :
63 : class CPLSafeIntOverflowDivisionByZero : public CPLSafeIntOverflow
64 : {
65 : public:
66 2 : inline CPLSafeIntOverflowDivisionByZero()
67 2 : {
68 2 : }
69 : };
70 :
71 : #if defined(__clang__)
72 : #pragma clang diagnostic pop
73 : #endif
74 :
75 : /** Convenience functions to build a CPLSafeInt */
76 1008 : inline CPLSafeInt<int> CPLSM(int x)
77 : {
78 1008 : return CPLSafeInt<int>(x);
79 : }
80 :
81 43 : inline CPLSafeInt<unsigned> CPLSM(unsigned x)
82 : {
83 43 : return CPLSafeInt<unsigned>(x);
84 : }
85 :
86 2 : inline CPLSafeInt<unsigned> CPLSM_TO_UNSIGNED(int x)
87 : {
88 2 : if (x < 0)
89 1 : throw CPLSafeIntOverflow();
90 1 : return CPLSafeInt<unsigned>(static_cast<unsigned>(x));
91 : }
92 :
93 611 : inline CPLSafeInt<int64_t> CPLSM(int64_t x)
94 : {
95 611 : return CPLSafeInt<int64_t>(x);
96 : }
97 :
98 88967 : inline CPLSafeInt<uint64_t> CPLSM(uint64_t x)
99 : {
100 88967 : return CPLSafeInt<uint64_t>(x);
101 : }
102 :
103 : // Unimplemented for now
104 : inline CPLSafeInt<unsigned> CPLSM_TO_UNSIGNED(unsigned x);
105 : inline CPLSafeInt<unsigned> CPLSM_TO_UNSIGNED(int64_t x);
106 : inline CPLSafeInt<unsigned> CPLSM_TO_UNSIGNED(uint64_t x);
107 :
108 : #if !defined(BUILTIN_OVERFLOW_CHECK_AVAILABLE) && defined(_MSC_VER)
109 : class CPLMSVCSafeIntException : public msl::utilities::SafeIntException
110 : {
111 : public:
112 : static void SafeIntOnOverflow()
113 : {
114 : throw CPLSafeIntOverflow();
115 : }
116 :
117 : static void SafeIntOnDivZero()
118 : {
119 : throw CPLSafeIntOverflowDivisionByZero();
120 : }
121 : };
122 : #endif
123 :
124 : template <class T>
125 : inline CPLSafeInt<T> SafeAddSigned(const CPLSafeInt<T> &A,
126 : const CPLSafeInt<T> &B)
127 : {
128 : const auto a = A.v();
129 : const auto b = B.v();
130 : if (a > 0 && b > 0 && a > std::numeric_limits<T>::max() - b)
131 : throw CPLSafeIntOverflow();
132 : if (a < 0 && b < 0 && a < std::numeric_limits<T>::min() - b)
133 : throw CPLSafeIntOverflow();
134 : return CPLSM(a + b);
135 : }
136 :
137 50 : inline CPLSafeInt<int> operator+(const CPLSafeInt<int> &A,
138 : const CPLSafeInt<int> &B)
139 : {
140 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
141 : int res;
142 50 : if (__builtin_sadd_overflow(A.v(), B.v(), &res))
143 4 : throw CPLSafeIntOverflow();
144 92 : return CPLSM(res);
145 : #elif defined(_MSC_VER)
146 : msl::utilities::SafeInt<int, CPLMSVCSafeIntException> A2(A.v());
147 : msl::utilities::SafeInt<int, CPLMSVCSafeIntException> B2(B.v());
148 : return CPLSM(static_cast<int>(A2 + B2));
149 : #else
150 : const int a = A.v();
151 : const int b = B.v();
152 : const int64_t res = static_cast<int64_t>(a) + b;
153 : if (res < std::numeric_limits<int>::min() ||
154 : res > std::numeric_limits<int>::max())
155 : {
156 : throw CPLSafeIntOverflow();
157 : }
158 : return CPLSM(static_cast<int>(res));
159 : #endif
160 : }
161 :
162 : #if defined(GDAL_COMPILATION)
163 103 : inline CPLSafeInt<int64_t> operator+(const CPLSafeInt<int64_t> &A,
164 : const CPLSafeInt<int64_t> &B)
165 : {
166 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
167 : long long res;
168 103 : if (__builtin_saddll_overflow(A.v(), B.v(), &res))
169 2 : throw CPLSafeIntOverflow();
170 202 : return CPLSM(static_cast<int64_t>(res));
171 : #elif defined(_MSC_VER)
172 : msl::utilities::SafeInt<int64_t, CPLMSVCSafeIntException> A2(A.v());
173 : msl::utilities::SafeInt<int64_t, CPLMSVCSafeIntException> B2(B.v());
174 : return CPLSM(static_cast<int64_t>(A2 + B2));
175 : #else
176 : return SafeAddSigned(A, B);
177 : #endif
178 : }
179 : #endif // GDAL_COMPILATION
180 :
181 3 : inline CPLSafeInt<unsigned> operator+(const CPLSafeInt<unsigned> &A,
182 : const CPLSafeInt<unsigned> &B)
183 : {
184 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
185 : unsigned res;
186 3 : if (__builtin_uadd_overflow(A.v(), B.v(), &res))
187 1 : throw CPLSafeIntOverflow();
188 4 : return CPLSM(res);
189 : #elif defined(_MSC_VER)
190 : msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> A2(A.v());
191 : msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> B2(B.v());
192 : return CPLSM(static_cast<unsigned>(A2 + B2));
193 : #else
194 : const unsigned a = A.v();
195 : const unsigned b = B.v();
196 : if (a > std::numeric_limits<unsigned>::max() - b)
197 : throw CPLSafeIntOverflow();
198 : return CPLSM(a + b);
199 : #endif
200 : }
201 :
202 : #if defined(GDAL_COMPILATION)
203 13879 : inline CPLSafeInt<uint64_t> operator+(const CPLSafeInt<uint64_t> &A,
204 : const CPLSafeInt<uint64_t> &B)
205 : {
206 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
207 : unsigned long long res;
208 13879 : if (__builtin_uaddll_overflow(A.v(), B.v(), &res))
209 1 : throw CPLSafeIntOverflow();
210 27756 : return CPLSM(static_cast<uint64_t>(res));
211 : #elif defined(_MSC_VER)
212 : msl::utilities::SafeInt<uint64_t, CPLMSVCSafeIntException> A2(A.v());
213 : msl::utilities::SafeInt<uint64_t, CPLMSVCSafeIntException> B2(B.v());
214 : return CPLSM(static_cast<uint64_t>(A2 + B2));
215 : #else
216 : const uint64_t a = A.v();
217 : const uint64_t b = B.v();
218 : if (a > std::numeric_limits<uint64_t>::max() - b)
219 : throw CPLSafeIntOverflow();
220 : return CPLSM(a + b);
221 : #endif
222 : }
223 : #endif // GDAL_COMPILATION
224 :
225 : template <class T>
226 : inline CPLSafeInt<T> SafeSubSigned(const CPLSafeInt<T> &A,
227 : const CPLSafeInt<T> &B)
228 : {
229 : const auto a = A.v();
230 : const auto b = B.v();
231 : /* caution we must catch a == 0 && b = INT_MIN */
232 : if (a >= 0 && b < 0 && a > std::numeric_limits<T>::max() + b)
233 : throw CPLSafeIntOverflow();
234 : if (a < 0 && b > 0 && a < std::numeric_limits<T>::min() + b)
235 : throw CPLSafeIntOverflow();
236 : return CPLSM(a - b);
237 : }
238 :
239 17 : inline CPLSafeInt<int> operator-(const CPLSafeInt<int> &A,
240 : const CPLSafeInt<int> &B)
241 : {
242 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
243 : int res;
244 17 : if (__builtin_ssub_overflow(A.v(), B.v(), &res))
245 3 : throw CPLSafeIntOverflow();
246 28 : return CPLSM(res);
247 : #elif defined(_MSC_VER)
248 : msl::utilities::SafeInt<int, CPLMSVCSafeIntException> A2(A.v());
249 : msl::utilities::SafeInt<int, CPLMSVCSafeIntException> B2(B.v());
250 : return CPLSM(static_cast<int>(A2 - B2));
251 : #else
252 : const int a = A.v();
253 : const int b = B.v();
254 : const int64_t res = static_cast<int64_t>(a) - b;
255 : if (res < std::numeric_limits<int>::min() ||
256 : res > std::numeric_limits<int>::max())
257 : {
258 : throw CPLSafeIntOverflow();
259 : }
260 : return CPLSM(static_cast<int>(res));
261 : #endif
262 : }
263 :
264 17 : inline CPLSafeInt<int64_t> operator-(const CPLSafeInt<int64_t> &A,
265 : const CPLSafeInt<int64_t> &B)
266 : {
267 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
268 : long long res;
269 17 : if (__builtin_ssubll_overflow(A.v(), B.v(), &res))
270 2 : throw CPLSafeIntOverflow();
271 30 : return CPLSM(static_cast<int64_t>(res));
272 : #elif defined(_MSC_VER)
273 : msl::utilities::SafeInt<int64_t, CPLMSVCSafeIntException> A2(A.v());
274 : msl::utilities::SafeInt<int64_t, CPLMSVCSafeIntException> B2(B.v());
275 : return CPLSM(static_cast<int64_t>(A2 - B2));
276 : #else
277 : return SafeSubSigned(A, B);
278 : #endif
279 : }
280 :
281 4 : inline CPLSafeInt<unsigned> operator-(const CPLSafeInt<unsigned> &A,
282 : const CPLSafeInt<unsigned> &B)
283 : {
284 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
285 : unsigned res;
286 4 : if (__builtin_usub_overflow(A.v(), B.v(), &res))
287 1 : throw CPLSafeIntOverflow();
288 6 : return CPLSM(res);
289 : #elif defined(_MSC_VER)
290 : msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> A2(A.v());
291 : msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> B2(B.v());
292 : return CPLSM(static_cast<unsigned>(A2 - B2));
293 : #else
294 : const unsigned a = A.v();
295 : const unsigned b = B.v();
296 : if (a < b)
297 : throw CPLSafeIntOverflow();
298 : return CPLSM(a - b);
299 : #endif
300 : }
301 :
302 : template <class T>
303 : inline CPLSafeInt<T> SafeMulSigned(const CPLSafeInt<T> &A,
304 : const CPLSafeInt<T> &B)
305 : {
306 : const auto a = A.v();
307 : const auto b = B.v();
308 : if (a > 0 && b > 0 && a > std::numeric_limits<T>::max() / b)
309 : throw CPLSafeIntOverflow();
310 : if (a > 0 && b < 0 && b < std::numeric_limits<T>::min() / a)
311 : throw CPLSafeIntOverflow();
312 : if (a < 0 && b > 0 && a < std::numeric_limits<T>::min() / b)
313 : throw CPLSafeIntOverflow();
314 : else if (a == std::numeric_limits<T>::min())
315 : {
316 : if (b != 0 && b != 1)
317 : throw CPLSafeIntOverflow();
318 : }
319 : else if (b == std::numeric_limits<T>::min())
320 : {
321 : if (a != 0 && a != 1)
322 : throw CPLSafeIntOverflow();
323 : }
324 : else if (a < 0 && b < 0 && -a > std::numeric_limits<T>::max() / (-b))
325 : throw CPLSafeIntOverflow();
326 :
327 : return CPLSM(a * b);
328 : }
329 :
330 273 : inline CPLSafeInt<int> operator*(const CPLSafeInt<int> &A,
331 : const CPLSafeInt<int> &B)
332 : {
333 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
334 : int res;
335 273 : if (__builtin_smul_overflow(A.v(), B.v(), &res))
336 6 : throw CPLSafeIntOverflow();
337 534 : return CPLSM(res);
338 : #elif defined(_MSC_VER)
339 : msl::utilities::SafeInt<int, CPLMSVCSafeIntException> A2(A.v());
340 : msl::utilities::SafeInt<int, CPLMSVCSafeIntException> B2(B.v());
341 : return CPLSM(static_cast<int>(A2 * B2));
342 : #else
343 : const int a = A.v();
344 : const int b = B.v();
345 : const int64_t res = static_cast<int64_t>(a) * b;
346 : if (res < std::numeric_limits<int>::min() ||
347 : res > std::numeric_limits<int>::max())
348 : {
349 : throw CPLSafeIntOverflow();
350 : }
351 : return CPLSM(static_cast<int>(res));
352 : #endif
353 : }
354 :
355 118 : inline CPLSafeInt<int64_t> operator*(const CPLSafeInt<int64_t> &A,
356 : const CPLSafeInt<int64_t> &B)
357 : {
358 : #if defined(BUILTIN_OVERFLOW_CHECK_AVAILABLE) && defined(__x86_64__)
359 : long long res;
360 118 : if (__builtin_smulll_overflow(A.v(), B.v(), &res))
361 7 : throw CPLSafeIntOverflow();
362 222 : return CPLSM(static_cast<int64_t>(res));
363 : #elif defined(_MSC_VER)
364 : msl::utilities::SafeInt<int64_t, CPLMSVCSafeIntException> A2(A.v());
365 : msl::utilities::SafeInt<int64_t, CPLMSVCSafeIntException> B2(B.v());
366 : return CPLSM(static_cast<int64_t>(A2 * B2));
367 : #else
368 : return SafeMulSigned(A, B);
369 : #endif
370 : }
371 :
372 6 : inline CPLSafeInt<unsigned> operator*(const CPLSafeInt<unsigned> &A,
373 : const CPLSafeInt<unsigned> &B)
374 : {
375 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
376 : unsigned res;
377 6 : if (__builtin_umul_overflow(A.v(), B.v(), &res))
378 2 : throw CPLSafeIntOverflow();
379 8 : return CPLSM(res);
380 : #elif defined(_MSC_VER)
381 : msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> A2(A.v());
382 : msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> B2(B.v());
383 : return CPLSM(static_cast<unsigned>(A2 * B2));
384 : #else
385 : const unsigned a = A.v();
386 : const unsigned b = B.v();
387 : const uint64_t res = static_cast<uint64_t>(a) * b;
388 : if (res > std::numeric_limits<unsigned>::max())
389 : {
390 : throw CPLSafeIntOverflow();
391 : }
392 : return CPLSM(static_cast<unsigned>(res));
393 : #endif
394 : }
395 :
396 22162 : inline CPLSafeInt<uint64_t> operator*(const CPLSafeInt<uint64_t> &A,
397 : const CPLSafeInt<uint64_t> &B)
398 : {
399 : #ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
400 : unsigned long long res;
401 22162 : if (__builtin_umulll_overflow(A.v(), B.v(), &res))
402 2 : throw CPLSafeIntOverflow();
403 44320 : return CPLSM(static_cast<uint64_t>(res));
404 : #elif defined(_MSC_VER)
405 : msl::utilities::SafeInt<uint64_t, CPLMSVCSafeIntException> A2(A.v());
406 : msl::utilities::SafeInt<uint64_t, CPLMSVCSafeIntException> B2(B.v());
407 : return CPLSM(static_cast<uint64_t>(A2 * B2));
408 : #else
409 : const uint64_t a = A.v();
410 : const uint64_t b = B.v();
411 : if (b > 0 && a > std::numeric_limits<uint64_t>::max() / b)
412 : throw CPLSafeIntOverflow();
413 : return CPLSM(a * b);
414 : #endif
415 : }
416 :
417 : template <class T>
418 23 : inline CPLSafeInt<T> SafeDivSigned(const CPLSafeInt<T> &A,
419 : const CPLSafeInt<T> &B)
420 : {
421 23 : const auto a = A.v();
422 23 : const auto b = B.v();
423 23 : if (b == 0)
424 1 : throw CPLSafeIntOverflowDivisionByZero();
425 22 : if (a == std::numeric_limits<T>::min() && b == -1)
426 2 : throw CPLSafeIntOverflow();
427 20 : return CPLSM(a / b);
428 : }
429 :
430 12 : inline CPLSafeInt<int> operator/(const CPLSafeInt<int> &A,
431 : const CPLSafeInt<int> &B)
432 : {
433 12 : return SafeDivSigned(A, B);
434 : }
435 :
436 11 : inline CPLSafeInt<int64_t> operator/(const CPLSafeInt<int64_t> &A,
437 : const CPLSafeInt<int64_t> &B)
438 : {
439 11 : return SafeDivSigned(A, B);
440 : }
441 :
442 3 : inline CPLSafeInt<unsigned> operator/(const CPLSafeInt<unsigned> &A,
443 : const CPLSafeInt<unsigned> &B)
444 : {
445 3 : const unsigned a = A.v();
446 3 : const unsigned b = B.v();
447 3 : if (b == 0)
448 1 : throw CPLSafeIntOverflowDivisionByZero();
449 2 : return CPLSM(a / b);
450 : }
451 :
452 : #endif // CPL_SAFEMATHS_INCLUDED
|