1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SkSafeMath_DEFINED 18 #define SkSafeMath_DEFINED 19 20 #include <cstddef> 21 #include <cstdint> 22 #include <limits> 23 24 // Copy of Skia's SafeMath API used to validate Mesh parameters to support 25 // deferred creation of SkMesh instances on RenderThread. 26 // SafeMath always check that a series of operations do not overflow. 27 // This must be correct for all platforms, because this is a check for safety at runtime. 28 29 class SafeMath { 30 public: 31 SafeMath() = default; 32 ok()33 bool ok() const { return fOK; } 34 explicit operator bool() const { return fOK; } 35 mul(size_t x,size_t y)36 size_t mul(size_t x, size_t y) { 37 return sizeof(size_t) == sizeof(uint64_t) ? mul64(x, y) : mul32(x, y); 38 } 39 add(size_t x,size_t y)40 size_t add(size_t x, size_t y) { 41 size_t result = x + y; 42 fOK &= result >= x; 43 return result; 44 } 45 46 /** 47 * Return a + b, unless this result is an overflow/underflow. In those cases, fOK will 48 * be set to false, and it is undefined what this returns. 49 */ addInt(int a,int b)50 int addInt(int a, int b) { 51 if (b < 0 && a < std::numeric_limits<int>::min() - b) { 52 fOK = false; 53 return a; 54 } else if (b > 0 && a > std::numeric_limits<int>::max() - b) { 55 fOK = false; 56 return a; 57 } 58 return a + b; 59 } 60 61 // These saturate to their results Add(size_t x,size_t y)62 static size_t Add(size_t x, size_t y) { 63 SafeMath tmp; 64 size_t sum = tmp.add(x, y); 65 return tmp.ok() ? sum : SIZE_MAX; 66 } 67 Mul(size_t x,size_t y)68 static size_t Mul(size_t x, size_t y) { 69 SafeMath tmp; 70 size_t prod = tmp.mul(x, y); 71 return tmp.ok() ? prod : SIZE_MAX; 72 } 73 74 private: mul32(uint32_t x,uint32_t y)75 uint32_t mul32(uint32_t x, uint32_t y) { 76 uint64_t bx = x; 77 uint64_t by = y; 78 uint64_t result = bx * by; 79 fOK &= result >> 32 == 0; 80 // Overflow information is capture in fOK. Return the result modulo 2^32. 81 return (uint32_t)result; 82 } 83 mul64(uint64_t x,uint64_t y)84 uint64_t mul64(uint64_t x, uint64_t y) { 85 if (x <= std::numeric_limits<uint64_t>::max() >> 32 && 86 y <= std::numeric_limits<uint64_t>::max() >> 32) { 87 return x * y; 88 } else { 89 auto hi = [](uint64_t x) { return x >> 32; }; 90 auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; }; 91 92 uint64_t lx_ly = lo(x) * lo(y); 93 uint64_t hx_ly = hi(x) * lo(y); 94 uint64_t lx_hy = lo(x) * hi(y); 95 uint64_t hx_hy = hi(x) * hi(y); 96 uint64_t result = 0; 97 result = this->add(lx_ly, (hx_ly << 32)); 98 result = this->add(result, (lx_hy << 32)); 99 fOK &= (hx_hy + (hx_ly >> 32) + (lx_hy >> 32)) == 0; 100 101 return result; 102 } 103 } 104 bool fOK = true; 105 }; 106 107 #endif // SkSafeMath_DEFINED 108