Home | History | Annotate | Download | only in source
      1 /*
      2  *
      3  * Copyright (C) 2015 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 // Functions for safe arithmetic (guarded against overflow) on integer types.
     19 
     20 #ifndef __dng_safe_arithmetic__
     21 #define __dng_safe_arithmetic__
     22 
     23 #include <cstddef>
     24 #include <cstdint>
     25 #include <limits>
     26 
     27 #include "dng_exceptions.h"
     28 
     29 #ifndef __has_builtin
     30 #define __has_builtin(x) 0  // Compatibility with non-Clang compilers.
     31 #endif
     32 
     33 #if !defined(DNG_HAS_INT128) && defined(__SIZEOF_INT128__)
     34 #define DNG_HAS_INT128
     35 #endif
     36 
     37 // If the result of adding arg1 and arg2 will fit in an int32_t (without
     38 // under-/overflow), stores this result in *result and returns true. Otherwise,
     39 // returns false and leaves *result unchanged.
     40 bool SafeInt32Add(std::int32_t arg1, std::int32_t arg2, std::int32_t *result);
     41 
     42 // Returns the result of adding arg1 and arg2 if it will fit in the result type
     43 // (without under-/overflow). Otherwise, throws a dng_exception with error code
     44 // dng_error_unknown.
     45 std::int32_t SafeInt32Add(std::int32_t arg1, std::int32_t arg2);
     46 std::int64_t SafeInt64Add(std::int64_t arg1, std::int64_t arg2);
     47 
     48 // If the result of adding arg1 and arg2 will fit in a uint32_t (without
     49 // wraparound), stores this result in *result and returns true. Otherwise,
     50 // returns false and leaves *result unchanged.
     51 bool SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2,
     52                    std::uint32_t *result);
     53 
     54 // Returns the result of adding arg1 and arg2 if it will fit in the result type
     55 // (without wraparound). Otherwise, throws a dng_exception with error code
     56 // dng_error_unknown.
     57 std::uint32_t SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2);
     58 std::uint64_t SafeUint64Add(std::uint64_t arg1, std::uint64_t arg2);
     59 
     60 // If the subtraction of arg2 from arg1 will not result in an int32_t under- or
     61 // overflow, stores this result in *result and returns true. Otherwise,
     62 // returns false and leaves *result unchanged.
     63 bool SafeInt32Sub(std::int32_t arg1, std::int32_t arg2, std::int32_t *result);
     64 
     65 // Returns the result of subtracting arg2 from arg1 if this operation will not
     66 // result in an int32_t under- or overflow. Otherwise, throws a dng_exception
     67 // with error code dng_error_unknown.
     68 std::int32_t SafeInt32Sub(std::int32_t arg1, std::int32_t arg2);
     69 
     70 // Returns the result of subtracting arg2 from arg1 if this operation will not
     71 // result in wraparound. Otherwise, throws a dng_exception with error code
     72 // dng_error_unknown.
     73 std::uint32_t SafeUint32Sub(std::uint32_t arg1, std::uint32_t arg2);
     74 
     75 // Returns the result of multiplying arg1 and arg2 if it will fit in a int32_t
     76 // (without overflow). Otherwise, throws a dng_exception with error code
     77 // dng_error_unknown.
     78 std::int32_t SafeInt32Mult(std::int32_t arg1, std::int32_t arg2);
     79 
     80 // If the result of multiplying arg1, ..., argn will fit in a uint32_t (without
     81 // wraparound), stores this result in *result and returns true. Otherwise,
     82 // returns false and leaves *result unchanged.
     83 bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
     84                     std::uint32_t *result);
     85 bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3,
     86                     std::uint32_t *result);
     87 bool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3,
     88                     std::uint32_t arg4, std::uint32_t *result);
     89 
     90 // Returns the result of multiplying arg1, ..., argn if it will fit in a
     91 // uint32_t (without wraparound). Otherwise, throws a dng_exception with error
     92 // code dng_error_unknown.
     93 std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2);
     94 std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
     95                              std::uint32_t arg3);
     96 std::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2,
     97                              std::uint32_t arg3, std::uint32_t arg4);
     98 
     99 // Returns the result of multiplying arg1 and arg2 if it will fit in a size_t
    100 // (without overflow). Otherwise, throws a dng_exception with error code
    101 // dng_error_unknown.
    102 std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2);
    103 
    104 namespace dng_internal {
    105 
    106 // Internal function used as fallback for SafeInt64Mult() if other optimized
    107 // computation is not supported. Don't call this function directly.
    108 std::int64_t SafeInt64MultSlow(std::int64_t arg1, std::int64_t arg2);
    109 
    110 // Internal function used as optimization for SafeInt64Mult() if Clang
    111 // __builtin_smull_overflow is supported. Don't call this function directly.
    112 #if __has_builtin(__builtin_smull_overflow)
    113 inline std::int64_t SafeInt64MultByClang(std::int64_t arg1, std::int64_t arg2) {
    114   std::int64_t result;
    115 #if (__WORDSIZE == 64) && !defined(__APPLE__)
    116   if (__builtin_smull_overflow(arg1, arg2, &result)) {
    117 #else
    118   if (__builtin_smulll_overflow(arg1, arg2, &result)) {
    119 #endif
    120     ThrowProgramError("Arithmetic overflow");
    121     abort();  // Never reached.
    122   }
    123   return result;
    124 }
    125 #endif
    126 
    127 // Internal function used as optimization for SafeInt64Mult() if __int128 type
    128 // is supported. Don't call this function directly.
    129 #ifdef DNG_HAS_INT128
    130 inline std::int64_t SafeInt64MultByInt128(std::int64_t arg1,
    131                                           std::int64_t arg2) {
    132   const __int128 kInt64Max =
    133       static_cast<__int128>(std::numeric_limits<std::int64_t>::max());
    134   const __int128 kInt64Min =
    135       static_cast<__int128>(std::numeric_limits<std::int64_t>::min());
    136   __int128 result = static_cast<__int128>(arg1) * static_cast<__int128>(arg2);
    137   if (result > kInt64Max || result < kInt64Min) {
    138     ThrowProgramError("Arithmetic overflow");
    139   }
    140   return static_cast<std::int64_t>(result);
    141 }
    142 #endif
    143 
    144 }  // namespace dng_internal
    145 
    146 // Returns the result of multiplying arg1 and arg2 if it will fit in an int64_t
    147 // (without overflow). Otherwise, throws a dng_exception with error code
    148 // dng_error_unknown.
    149 inline std::int64_t SafeInt64Mult(std::int64_t arg1, std::int64_t arg2) {
    150 #if __has_builtin(__builtin_smull_overflow)
    151   return dng_internal::SafeInt64MultByClang(arg1, arg2);
    152 #elif defined(DNG_HAS_INT128)
    153   return dng_internal::SafeInt64MultByInt128(arg1, arg2);
    154 #else
    155   return dng_internal::SafeInt64MultSlow(arg1, arg2);
    156 #endif
    157 }
    158 
    159 // Returns the result of dividing arg1 by arg2; if the result is not an integer,
    160 // rounds up to the next integer. If arg2 is zero, throws a dng_exception with
    161 // error code dng_error_unknown.
    162 // The function is safe against wraparound and will return the correct result
    163 // for all combinations of arg1 and arg2.
    164 std::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2);
    165 
    166 // Finds the smallest integer multiple of 'multiple_of' that is greater than or
    167 // equal to 'val'. If this value will fit in a uint32_t, stores it in *result
    168 // and returns true. Otherwise, or if 'multiple_of' is zero, returns false and
    169 // leaves *result unchanged.
    170 bool RoundUpUint32ToMultiple(std::uint32_t val, std::uint32_t multiple_of,
    171                              std::uint32_t *result);
    172 
    173 // Returns the smallest integer multiple of 'multiple_of' that is greater than
    174 // or equal to 'val'. If the result will not fit in a std::uint32_t or if
    175 // 'multiple_of' is zero, throws a dng_exception with error code
    176 // dng_error_unknown.
    177 std::uint32_t RoundUpUint32ToMultiple(std::uint32_t val,
    178                                       std::uint32_t multiple_of);
    179 
    180 // If the uint32_t value val will fit in a int32_t, converts it to a int32_t and
    181 // stores it in *result. Otherwise, returns false and leaves *result unchanged.
    182 bool ConvertUint32ToInt32(std::uint32_t val, std::int32_t *result);
    183 
    184 // Returns the result of converting val to an int32_t if it can be converted
    185 // without overflow. Otherwise, throws a dng_exception with error code
    186 // dng_error_unknown.
    187 std::int32_t ConvertUint32ToInt32(std::uint32_t val);
    188 
    189 // Converts a value of the unsigned integer type TSrc to the unsigned integer
    190 // type TDest. If the value in 'src' cannot be converted to the type TDest
    191 // without truncation, throws a dng_exception with error code dng_error_unknown.
    192 //
    193 // Note: Though this function is typically used where TDest is a narrower type
    194 // than TSrc, it is designed to work also if TDest is wider than from TSrc or
    195 // identical to TSrc. This is useful in situations where the width of the types
    196 // involved can change depending on the architecture -- for example, the
    197 // conversion from size_t to uint32_t may either be narrowing, identical or even
    198 // widening (though the latter admittedly happens only on architectures that
    199 // aren't relevant to us).
    200 template <class TSrc, class TDest>
    201 static void ConvertUnsigned(TSrc src, TDest *dest) {
    202   static_assert(std::numeric_limits<TSrc>::is_integer &&
    203                     !std::numeric_limits<TSrc>::is_signed &&
    204                     std::numeric_limits<TDest>::is_integer &&
    205                     !std::numeric_limits<TDest>::is_signed,
    206                 "TSrc and TDest must be unsigned integer types");
    207 
    208   const TDest converted = static_cast<TDest>(src);
    209 
    210   // Convert back to TSrc to check whether truncation occurred in the
    211   // conversion to TDest.
    212   if (static_cast<TSrc>(converted) != src) {
    213     ThrowProgramError("Overflow in unsigned integer conversion");
    214   }
    215 
    216   *dest = converted;
    217 }
    218 
    219 // Returns the result of converting val to the result type using truncation if
    220 // val is in range of the result type values. Otherwise, throws a dng_exception
    221 // with error code dng_error_unknown.
    222 std::int32_t ConvertDoubleToInt32(double val);
    223 std::uint32_t ConvertDoubleToUint32(double val);
    224 
    225 // Returns the result of converting val to float. If val is outside of
    226 // [-FLT_MAX, FLT_MAX], -infinity and infinity is returned respectively. NaN is
    227 // returned as NaN.
    228 float ConvertDoubleToFloat(double val);
    229 
    230 #endif  // __dng_safe_arithmetic__
    231