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