LCOV - code coverage report
Current view: top level - port - cpl_safemaths.hpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 84 84 100.0 %
Date: 2025-07-09 17:50:03 Functions: 31 31 100.0 %

          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

Generated by: LCOV version 1.14