Coverage Report

Created: 2025-06-13 06:29

/src/gdal/port/cpl_safemaths.hpp
Line
Count
Source (jump to first uncovered line)
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
0
    inline explicit CPLSafeInt(T valIn) : val(valIn)
46
0
    {
47
0
    }
Unexecuted instantiation: CPLSafeInt<unsigned long>::CPLSafeInt(unsigned long)
Unexecuted instantiation: CPLSafeInt<long>::CPLSafeInt(long)
48
49
    inline T v() const
50
0
    {
51
0
        return val;
52
0
    }
Unexecuted instantiation: CPLSafeInt<unsigned long>::v() const
Unexecuted instantiation: CPLSafeInt<int>::v() const
Unexecuted instantiation: CPLSafeInt<long>::v() const
Unexecuted instantiation: CPLSafeInt<unsigned int>::v() const
53
};
54
55
class CPLSafeIntOverflow : public std::exception
56
{
57
  public:
58
    inline CPLSafeIntOverflow()
59
0
    {
60
0
    }
61
};
62
63
class CPLSafeIntOverflowDivisionByZero : public CPLSafeIntOverflow
64
{
65
  public:
66
    inline CPLSafeIntOverflowDivisionByZero()
67
0
    {
68
0
    }
69
};
70
71
#if defined(__clang__)
72
#pragma clang diagnostic pop
73
#endif
74
75
/** Convenience functions to build a CPLSafeInt */
76
inline CPLSafeInt<int> CPLSM(int x)
77
0
{
78
0
    return CPLSafeInt<int>(x);
79
0
}
80
81
inline CPLSafeInt<unsigned> CPLSM(unsigned x)
82
0
{
83
0
    return CPLSafeInt<unsigned>(x);
84
0
}
85
86
inline CPLSafeInt<unsigned> CPLSM_TO_UNSIGNED(int x)
87
0
{
88
0
    if (x < 0)
89
0
        throw CPLSafeIntOverflow();
90
0
    return CPLSafeInt<unsigned>(static_cast<unsigned>(x));
91
0
}
92
93
inline CPLSafeInt<int64_t> CPLSM(int64_t x)
94
0
{
95
0
    return CPLSafeInt<int64_t>(x);
96
0
}
97
98
inline CPLSafeInt<uint64_t> CPLSM(uint64_t x)
99
0
{
100
0
    return CPLSafeInt<uint64_t>(x);
101
0
}
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
inline CPLSafeInt<int> operator+(const CPLSafeInt<int> &A,
138
                                 const CPLSafeInt<int> &B)
139
0
{
140
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
141
0
    int res;
142
0
    if (__builtin_sadd_overflow(A.v(), B.v(), &res))
143
0
        throw CPLSafeIntOverflow();
144
0
    return CPLSM(res);
145
0
#elif defined(_MSC_VER)
146
0
    msl::utilities::SafeInt<int, CPLMSVCSafeIntException> A2(A.v());
147
0
    msl::utilities::SafeInt<int, CPLMSVCSafeIntException> B2(B.v());
148
0
    return CPLSM(static_cast<int>(A2 + B2));
149
0
#else
150
0
    const int a = A.v();
151
0
    const int b = B.v();
152
0
    const int64_t res = static_cast<int64_t>(a) + b;
153
0
    if (res < std::numeric_limits<int>::min() ||
154
0
        res > std::numeric_limits<int>::max())
155
0
    {
156
0
        throw CPLSafeIntOverflow();
157
0
    }
158
0
    return CPLSM(static_cast<int>(res));
159
0
#endif
160
0
}
161
162
#if defined(GDAL_COMPILATION)
163
inline CPLSafeInt<int64_t> operator+(const CPLSafeInt<int64_t> &A,
164
                                     const CPLSafeInt<int64_t> &B)
165
0
{
166
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
167
0
    long long res;
168
0
    if (__builtin_saddll_overflow(A.v(), B.v(), &res))
169
0
        throw CPLSafeIntOverflow();
170
0
    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
0
}
179
#endif  // GDAL_COMPILATION
180
181
inline CPLSafeInt<unsigned> operator+(const CPLSafeInt<unsigned> &A,
182
                                      const CPLSafeInt<unsigned> &B)
183
0
{
184
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
185
0
    unsigned res;
186
0
    if (__builtin_uadd_overflow(A.v(), B.v(), &res))
187
0
        throw CPLSafeIntOverflow();
188
0
    return CPLSM(res);
189
0
#elif defined(_MSC_VER)
190
0
    msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> A2(A.v());
191
0
    msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> B2(B.v());
192
0
    return CPLSM(static_cast<unsigned>(A2 + B2));
193
0
#else
194
0
    const unsigned a = A.v();
195
0
    const unsigned b = B.v();
196
0
    if (a > std::numeric_limits<unsigned>::max() - b)
197
0
        throw CPLSafeIntOverflow();
198
0
    return CPLSM(a + b);
199
0
#endif
200
0
}
201
202
#if defined(GDAL_COMPILATION)
203
inline CPLSafeInt<uint64_t> operator+(const CPLSafeInt<uint64_t> &A,
204
                                      const CPLSafeInt<uint64_t> &B)
205
0
{
206
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
207
0
    unsigned long long res;
208
0
    if (__builtin_uaddll_overflow(A.v(), B.v(), &res))
209
0
        throw CPLSafeIntOverflow();
210
0
    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
0
}
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
inline CPLSafeInt<int> operator-(const CPLSafeInt<int> &A,
240
                                 const CPLSafeInt<int> &B)
241
0
{
242
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
243
0
    int res;
244
0
    if (__builtin_ssub_overflow(A.v(), B.v(), &res))
245
0
        throw CPLSafeIntOverflow();
246
0
    return CPLSM(res);
247
0
#elif defined(_MSC_VER)
248
0
    msl::utilities::SafeInt<int, CPLMSVCSafeIntException> A2(A.v());
249
0
    msl::utilities::SafeInt<int, CPLMSVCSafeIntException> B2(B.v());
250
0
    return CPLSM(static_cast<int>(A2 - B2));
251
0
#else
252
0
    const int a = A.v();
253
0
    const int b = B.v();
254
0
    const int64_t res = static_cast<int64_t>(a) - b;
255
0
    if (res < std::numeric_limits<int>::min() ||
256
0
        res > std::numeric_limits<int>::max())
257
0
    {
258
0
        throw CPLSafeIntOverflow();
259
0
    }
260
0
    return CPLSM(static_cast<int>(res));
261
0
#endif
262
0
}
263
264
inline CPLSafeInt<int64_t> operator-(const CPLSafeInt<int64_t> &A,
265
                                     const CPLSafeInt<int64_t> &B)
266
0
{
267
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
268
0
    long long res;
269
0
    if (__builtin_ssubll_overflow(A.v(), B.v(), &res))
270
0
        throw CPLSafeIntOverflow();
271
0
    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
0
}
280
281
inline CPLSafeInt<unsigned> operator-(const CPLSafeInt<unsigned> &A,
282
                                      const CPLSafeInt<unsigned> &B)
283
0
{
284
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
285
0
    unsigned res;
286
0
    if (__builtin_usub_overflow(A.v(), B.v(), &res))
287
0
        throw CPLSafeIntOverflow();
288
0
    return CPLSM(res);
289
0
#elif defined(_MSC_VER)
290
0
    msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> A2(A.v());
291
0
    msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> B2(B.v());
292
0
    return CPLSM(static_cast<unsigned>(A2 - B2));
293
0
#else
294
0
    const unsigned a = A.v();
295
0
    const unsigned b = B.v();
296
0
    if (a < b)
297
0
        throw CPLSafeIntOverflow();
298
0
    return CPLSM(a - b);
299
0
#endif
300
0
}
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
inline CPLSafeInt<int> operator*(const CPLSafeInt<int> &A,
331
                                 const CPLSafeInt<int> &B)
332
0
{
333
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
334
0
    int res;
335
0
    if (__builtin_smul_overflow(A.v(), B.v(), &res))
336
0
        throw CPLSafeIntOverflow();
337
0
    return CPLSM(res);
338
0
#elif defined(_MSC_VER)
339
0
    msl::utilities::SafeInt<int, CPLMSVCSafeIntException> A2(A.v());
340
0
    msl::utilities::SafeInt<int, CPLMSVCSafeIntException> B2(B.v());
341
0
    return CPLSM(static_cast<int>(A2 * B2));
342
0
#else
343
0
    const int a = A.v();
344
0
    const int b = B.v();
345
0
    const int64_t res = static_cast<int64_t>(a) * b;
346
0
    if (res < std::numeric_limits<int>::min() ||
347
0
        res > std::numeric_limits<int>::max())
348
0
    {
349
0
        throw CPLSafeIntOverflow();
350
0
    }
351
0
    return CPLSM(static_cast<int>(res));
352
0
#endif
353
0
}
354
355
inline CPLSafeInt<int64_t> operator*(const CPLSafeInt<int64_t> &A,
356
                                     const CPLSafeInt<int64_t> &B)
357
0
{
358
0
#if defined(BUILTIN_OVERFLOW_CHECK_AVAILABLE) && defined(__x86_64__)
359
0
    long long res;
360
0
    if (__builtin_smulll_overflow(A.v(), B.v(), &res))
361
0
        throw CPLSafeIntOverflow();
362
0
    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
0
}
371
372
inline CPLSafeInt<unsigned> operator*(const CPLSafeInt<unsigned> &A,
373
                                      const CPLSafeInt<unsigned> &B)
374
0
{
375
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
376
0
    unsigned res;
377
0
    if (__builtin_umul_overflow(A.v(), B.v(), &res))
378
0
        throw CPLSafeIntOverflow();
379
0
    return CPLSM(res);
380
0
#elif defined(_MSC_VER)
381
0
    msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> A2(A.v());
382
0
    msl::utilities::SafeInt<unsigned, CPLMSVCSafeIntException> B2(B.v());
383
0
    return CPLSM(static_cast<unsigned>(A2 * B2));
384
0
#else
385
0
    const unsigned a = A.v();
386
0
    const unsigned b = B.v();
387
0
    const uint64_t res = static_cast<uint64_t>(a) * b;
388
0
    if (res > std::numeric_limits<unsigned>::max())
389
0
    {
390
0
        throw CPLSafeIntOverflow();
391
0
    }
392
0
    return CPLSM(static_cast<unsigned>(res));
393
0
#endif
394
0
}
395
396
inline CPLSafeInt<uint64_t> operator*(const CPLSafeInt<uint64_t> &A,
397
                                      const CPLSafeInt<uint64_t> &B)
398
0
{
399
0
#ifdef BUILTIN_OVERFLOW_CHECK_AVAILABLE
400
0
    unsigned long long res;
401
0
    if (__builtin_umulll_overflow(A.v(), B.v(), &res))
402
0
        throw CPLSafeIntOverflow();
403
0
    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
0
}
416
417
template <class T>
418
inline CPLSafeInt<T> SafeDivSigned(const CPLSafeInt<T> &A,
419
                                   const CPLSafeInt<T> &B)
420
0
{
421
0
    const auto a = A.v();
422
0
    const auto b = B.v();
423
0
    if (b == 0)
424
0
        throw CPLSafeIntOverflowDivisionByZero();
425
0
    if (a == std::numeric_limits<T>::min() && b == -1)
426
0
        throw CPLSafeIntOverflow();
427
0
    return CPLSM(a / b);
428
0
}
Unexecuted instantiation: CPLSafeInt<int> SafeDivSigned<int>(CPLSafeInt<int> const&, CPLSafeInt<int> const&)
Unexecuted instantiation: CPLSafeInt<long> SafeDivSigned<long>(CPLSafeInt<long> const&, CPLSafeInt<long> const&)
429
430
inline CPLSafeInt<int> operator/(const CPLSafeInt<int> &A,
431
                                 const CPLSafeInt<int> &B)
432
0
{
433
0
    return SafeDivSigned(A, B);
434
0
}
435
436
inline CPLSafeInt<int64_t> operator/(const CPLSafeInt<int64_t> &A,
437
                                     const CPLSafeInt<int64_t> &B)
438
0
{
439
0
    return SafeDivSigned(A, B);
440
0
}
441
442
inline CPLSafeInt<unsigned> operator/(const CPLSafeInt<unsigned> &A,
443
                                      const CPLSafeInt<unsigned> &B)
444
0
{
445
0
    const unsigned a = A.v();
446
0
    const unsigned b = B.v();
447
0
    if (b == 0)
448
0
        throw CPLSafeIntOverflowDivisionByZero();
449
0
    return CPLSM(a / b);
450
0
}
451
452
#endif  // CPL_SAFEMATHS_INCLUDED