xref: /aosp_15_r20/frameworks/base/libs/hwui/SafeMath.h (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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