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