1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkSafeMath_DEFINED 9 #define SkSafeMath_DEFINED 10 11 #include "SkTypes.h" 12 13 // SkSafeMath always check that a series of operations do not overflow. 14 // This must be correct for all platforms, because this is a check for safety at runtime. 15 16 class SkSafeMath { 17 public: 18 SkSafeMath() = default; 19 ok()20 bool ok() const { return fOK; } 21 explicit operator bool() const { return fOK; } 22 mul(size_t x,size_t y)23 size_t mul(size_t x, size_t y) { 24 return sizeof(size_t) == sizeof(uint64_t) ? mul64(x, y) : mul32(x, y); 25 } 26 add(size_t x,size_t y)27 size_t add(size_t x, size_t y) { 28 size_t result = x + y; 29 fOK &= result >= x; 30 return result; 31 } 32 33 /** 34 * Return a + b, unless this result is an overflow/underflow. In those cases, fOK will 35 * be set to false, and it is undefined what this returns. 36 */ addInt(int a,int b)37 int addInt(int a, int b) { 38 if (b < 0 && a < std::numeric_limits<int>::min() - b) { 39 fOK = false; 40 return a; 41 } else if (b > 0 && a > std::numeric_limits<int>::max() - b) { 42 fOK = false; 43 return a; 44 } 45 return a + b; 46 } 47 alignUp(size_t x,size_t alignment)48 size_t alignUp(size_t x, size_t alignment) { 49 SkASSERT(alignment && !(alignment & (alignment - 1))); 50 return add(x, alignment - 1) & ~(alignment - 1); 51 } 52 castTo(size_t value)53 template <typename T> T castTo(size_t value) { 54 if (!SkTFitsIn<T>(value)) { 55 fOK = false; 56 } 57 return static_cast<T>(value); 58 } 59 60 // These saturate to their results 61 static size_t Add(size_t x, size_t y); 62 static size_t Mul(size_t x, size_t y); Align4(size_t x)63 static size_t Align4(size_t x) { 64 SkSafeMath safe; 65 return safe.alignUp(x, 4); 66 } 67 68 private: mul32(uint32_t x,uint32_t y)69 uint32_t mul32(uint32_t x, uint32_t y) { 70 uint64_t bx = x; 71 uint64_t by = y; 72 uint64_t result = bx * by; 73 fOK &= result >> 32 == 0; 74 return result; 75 } 76 mul64(uint64_t x,uint64_t y)77 uint64_t mul64(uint64_t x, uint64_t y) { 78 if (x <= std::numeric_limits<uint64_t>::max() >> 32 79 && y <= std::numeric_limits<uint64_t>::max() >> 32) { 80 return x * y; 81 } else { 82 auto hi = [](uint64_t x) { return x >> 32; }; 83 auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; }; 84 85 uint64_t lx_ly = lo(x) * lo(y); 86 uint64_t hx_ly = hi(x) * lo(y); 87 uint64_t lx_hy = lo(x) * hi(y); 88 uint64_t hx_hy = hi(x) * hi(y); 89 uint64_t result = 0; 90 result = this->add(lx_ly, (hx_ly << 32)); 91 result = this->add(result, (lx_hy << 32)); 92 fOK &= (hx_hy + (hx_ly >> 32) + (lx_hy >> 32)) == 0; 93 94 #if defined(SK_DEBUG) && defined(__clang__) && defined(__x86_64__) 95 auto double_check = (unsigned __int128)x * y; 96 SkASSERT(result == (double_check & 0xFFFFFFFFFFFFFFFF)); 97 SkASSERT(!fOK || (double_check >> 64 == 0)); 98 #endif 99 100 return result; 101 } 102 } 103 bool fOK = true; 104 }; 105 106 #endif//SkSafeMath_DEFINED 107