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