16e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_safe_arithmetic.h" 26e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 31754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener#include <cmath> 46e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include <limits> 56e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 66e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim#include "dng_exceptions.h" 76e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 86e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Implementation of safe integer arithmetic follows guidelines from 96e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap 106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// and 116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow 126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimnamespace { 146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Template functions for safe arithmetic. These functions are not exposed in 166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// the header for the time being to avoid having to add checks for the various 176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// constraints on the template argument (e.g. that it is integral and possibly 186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// signed or unsigned only). This should be done using a static_assert(), but 196e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// we want to be portable to pre-C++11 compilers. 206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of adding arg1 and arg2 if it will fit in a T (where T is 226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// a signed or unsigned integer type). Otherwise, throws a dng_exception with 236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// error code dng_error_unknown. 246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimtemplate <class T> 256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan HakimT SafeAdd(T arg1, T arg2) { 266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // The condition is reformulated relative to the version on 276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // www.securecoding.cert.org to check for valid instead of invalid cases. It 286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // seems safer to enumerate the valid cases (and potentially miss one) than 296e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // enumerate the invalid cases. 306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // If T is an unsigned type, the second half of the condition always evaluates 316e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // to false and will presumably be compiled out by the compiler. 326e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if ((arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) || 336e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim (arg1 < 0 && arg2 >= std::numeric_limits<T>::min() - arg1)) { 346e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return arg1 + arg2; 356e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 366e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim ThrowProgramError("Arithmetic overflow"); 37c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 386e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 396e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 406e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 416e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// Returns the result of multiplying arg1 and arg2 if it will fit in a T (where 426e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// T is an unsigned integer type). Otherwise, throws a dng_exception with error 436e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim// code dng_error_unknown. 446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimtemplate <class T> 456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan HakimT SafeUnsignedMult(T arg1, T arg2) { 466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (arg1 == 0 || arg2 <= std::numeric_limits<T>::max() / arg1) { 476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return arg1 * arg2; 486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 496e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim ThrowProgramError("Arithmetic overflow"); 50c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 546e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} // namespace 556e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 566e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeInt32Add(std::int32_t arg1, std::int32_t arg2, std::int32_t *result) { 576e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim try { 586e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim *result = SafeInt32Add(arg1, arg2); 596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return true; 606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } catch (const dng_exception &) { 616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return false; 626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::int32_t SafeInt32Add(std::int32_t arg1, std::int32_t arg2) { 666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return SafeAdd<std::int32_t>(arg1, arg2); 676e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 686e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 696e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::int64_t SafeInt64Add(std::int64_t arg1, std::int64_t arg2) { 706e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return SafeAdd<std::int64_t>(arg1, arg2); 716e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 726e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 736e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2, 746e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result) { 756e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim try { 766e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim *result = SafeUint32Add(arg1, arg2); 776e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return true; 786e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } catch (const dng_exception &) { 796e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return false; 806e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 816e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 826e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Add(std::uint32_t arg1, std::uint32_t arg2) { 846e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return SafeAdd<std::uint32_t>(arg1, arg2); 856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 866e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 87c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::uint64_t SafeUint64Add(std::uint64_t arg1, std::uint64_t arg2) { 88c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return SafeAdd<std::uint64_t>(arg1, arg2); 89c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 90c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 916e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeInt32Sub(std::int32_t arg1, std::int32_t arg2, std::int32_t *result) { 926e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if ((arg2 >= 0 && arg1 >= std::numeric_limits<int32_t>::min() + arg2) || 936e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim (arg2 < 0 && arg1 <= std::numeric_limits<int32_t>::max() + arg2)) { 946e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim *result = arg1 - arg2; 956e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return true; 966e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 976e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return false; 986e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 996e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1006e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1016e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::int32_t SafeInt32Sub(std::int32_t arg1, std::int32_t arg2) { 1026e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::int32_t result = 0; 1036e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1046e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (!SafeInt32Sub(arg1, arg2, &result)) { 1056e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim ThrowProgramError("Arithmetic overflow"); 1066e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 1076e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1086e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return result; 1096e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 111c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::uint32_t SafeUint32Sub(std::uint32_t arg1, std::uint32_t arg2) { 112c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener if (arg1 >= arg2) { 113c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return arg1 - arg2; 114c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } else { 115c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener ThrowProgramError("Arithmetic overflow"); 116c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 117c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } 118c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 119c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 1206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, 1216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result) { 1226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim try { 1236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim *result = SafeUint32Mult(arg1, arg2); 1246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return true; 1256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } catch (const dng_exception &) { 1266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return false; 1276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 1286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1296e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3, 1316e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result) { 1326e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim try { 1336e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim *result = SafeUint32Mult(arg1, arg2, arg3); 1346e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return true; 1356e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } catch (const dng_exception &) { 1366e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return false; 1376e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 1386e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1396e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1406e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, std::uint32_t arg3, 1416e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t arg4, std::uint32_t *result) { 1426e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim try { 1436e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim *result = SafeUint32Mult(arg1, arg2, arg3, arg4); 1446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return true; 1456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } catch (const dng_exception &) { 1466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return false; 1476e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 1486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1496e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1506e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2) { 1516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return SafeUnsignedMult<std::uint32_t>(arg1, arg2); 1526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1546e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, 1556e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t arg3) { 1566e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return SafeUint32Mult(SafeUint32Mult(arg1, arg2), arg3); 1576e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1586e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1596e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32Mult(std::uint32_t arg1, std::uint32_t arg2, 1606e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t arg3, std::uint32_t arg4) { 1616e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return SafeUint32Mult(SafeUint32Mult(arg1, arg2, arg3), arg4); 1626e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 164c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int32_t SafeInt32Mult(std::int32_t arg1, std::int32_t arg2) { 165c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener const std::int64_t tmp = 166c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener static_cast<std::int64_t>(arg1) * static_cast<std::int64_t>(arg2); 167089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin if (tmp >= std::numeric_limits<std::int32_t>::min() && 168089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin tmp <= std::numeric_limits<std::int32_t>::max()) { 169c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return static_cast<std::int32_t>(tmp); 170c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } else { 171c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener ThrowProgramError("Arithmetic overflow"); 172c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); 173c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } 174c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 175c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 1766e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2) { 1776e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return SafeUnsignedMult<std::size_t>(arg1, arg2); 1786e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 1796e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 180c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienernamespace dng_internal { 181c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 182c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int64_t SafeInt64MultSlow(std::int64_t arg1, std::int64_t arg2) { 1836e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim bool overflow = true; 1846e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 1856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (arg1 > 0) { 1866e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (arg2 > 0) { 187089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin overflow = (arg1 > std::numeric_limits<std::int64_t>::max() / arg2); 1886e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 189089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin overflow = (arg2 < std::numeric_limits<std::int64_t>::min() / arg1); 1906e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 1916e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 1926e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (arg2 > 0) { 193089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin overflow = (arg1 < std::numeric_limits<std::int64_t>::min() / arg2); 1946e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 195089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin overflow = (arg1 != 0 && 196089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin arg2 < std::numeric_limits<std::int64_t>::max() / arg1); 1976e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 1986e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 1996e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2006e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (overflow) { 2016e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim ThrowProgramError("Arithmetic overflow"); 202c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 2036e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 2046e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return arg1 * arg2; 2056e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 2066e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 2076e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 208c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} // namespace dng_internal 209c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 2106e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimstd::uint32_t SafeUint32DivideUp(std::uint32_t arg1, std::uint32_t arg2) { 2116e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // It might seem more intuitive to implement this function simply as 2126e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // 2136e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // return arg2 == 0 ? 0 : (arg1 + arg2 - 1) / arg2; 2146e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // 2156e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // but the expression "arg1 + arg2" can wrap around. 2166e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2176e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (arg2 == 0) { 2186e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim ThrowProgramError("Division by zero"); 219c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 2206e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else if (arg1 == 0) { 2216e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // If arg1 is zero, return zero to avoid wraparound in the expression 2226e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim // "arg1 - 1" below. 2236e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return 0; 2246e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 2256e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim return (arg1 - 1) / arg2 + 1; 2266e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 2276e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 2286e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2296e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool RoundUpUint32ToMultiple(std::uint32_t val, std::uint32_t multiple_of, 2306e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim std::uint32_t *result) { 231c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener try { 232c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener *result = RoundUpUint32ToMultiple(val, multiple_of); 233c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return true; 234c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } catch (const dng_exception &) { 23529c7498fabe2e3c87a85b487bfe9d783c401e1f0Yujie Qin return false; 236a9912faa4ebc5100cfb7f03718304a315edf32fbFlorian Kriener } 237c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 238c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 239c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::uint32_t RoundUpUint32ToMultiple(std::uint32_t val, 240c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener std::uint32_t multiple_of) { 241c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener if (multiple_of == 0) { 242c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener ThrowProgramError("multiple_of is zero in RoundUpUint32ToMultiple"); 243c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } 2446e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2456e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim const std::uint32_t remainder = val % multiple_of; 2466e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (remainder == 0) { 247c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return val; 2486e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } else { 249c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return SafeUint32Add(val, multiple_of - remainder); 2506e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 2516e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 2526e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2536e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakimbool ConvertUint32ToInt32(std::uint32_t val, std::int32_t *result) { 254c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener try { 255c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener *result = ConvertUint32ToInt32(val); 256c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return true; 257c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } catch (const dng_exception &) { 258c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return false; 259c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } 260c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 261c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 262c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int32_t ConvertUint32ToInt32(std::uint32_t val) { 2636e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim const std::uint32_t kInt32MaxAsUint32 = 2646e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim static_cast<std::uint32_t>(std::numeric_limits<std::int32_t>::max()); 2656e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim 2666e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim if (val <= kInt32MaxAsUint32) { 267c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return static_cast<std::int32_t>(val); 268a9912faa4ebc5100cfb7f03718304a315edf32fbFlorian Kriener } else { 269c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener ThrowProgramError("Arithmetic overflow"); 270c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 271c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } 272c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener} 273c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener 274c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Krienerstd::int32_t ConvertDoubleToInt32(double val) { 275089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin const double kMin = 276089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin static_cast<double>(std::numeric_limits<std::int32_t>::min()); 277089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin const double kMax = 278089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin static_cast<double>(std::numeric_limits<std::int32_t>::max()); 279c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener // NaNs will fail this test; they always compare false. 280c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener if (val > kMin - 1.0 && val < kMax + 1.0) { 281c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener return static_cast<std::int32_t>(val); 282c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener } else { 283c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener ThrowProgramError("Argument not in range in ConvertDoubleToInt32"); 284c89552e7ed1e0ea69c69addf2bb5de011188d297Florian Kriener abort(); // Never reached. 2856e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim } 2866e09dfbee0b1643a5cb2b32d0399c1a0c69551a0Kinan Hakim} 287089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin 288089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qinstd::uint32_t ConvertDoubleToUint32(double val) { 289089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin const double kMax = 290089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin static_cast<double>(std::numeric_limits<std::uint32_t>::max()); 291089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin // NaNs will fail this test; they always compare false. 292089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin if (val >= 0.0 && val < kMax + 1.0) { 293089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin return static_cast<std::uint32_t>(val); 294089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin } else { 295089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin ThrowProgramError("Argument not in range in ConvertDoubleToUint32"); 296089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin abort(); // Never reached. 297089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin } 298089babbee3f41a18e7940fa86fe4f3cfa45bc6eaYujie Qin} 2991754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener 3001754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Krienerfloat ConvertDoubleToFloat(double val) { 3011754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener const double kMax = std::numeric_limits<float>::max(); 3021754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener if (val > kMax) { 3031754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener return std::numeric_limits<float>::infinity(); 3041754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener } else if (val < -kMax) { 3051754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener return -std::numeric_limits<float>::infinity(); 3061754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener } else { 3071754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener // The cases that end up here are: 3081754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener // - values in [-kMax, kMax] 3091754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener // - NaN (because it always compares false) 3101754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener return static_cast<float>(val); 3111754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener } 3121754202ed3e25b98179a4f377f0bdd605d9a157aFlorian Kriener} 313