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: 2024-11-21 22:18:42 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             : #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

Generated by: LCOV version 1.14