/proc/self/cwd/internal/overflow.cc
Line | Count | Source |
1 | | // Copyright 2021 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include "internal/overflow.h" |
16 | | |
17 | | #include <cmath> |
18 | | #include <cstdint> |
19 | | #include <limits> |
20 | | |
21 | | #include "absl/status/status.h" |
22 | | #include "absl/status/statusor.h" |
23 | | #include "absl/time/time.h" |
24 | | #include "internal/status_macros.h" |
25 | | #include "internal/time.h" |
26 | | |
27 | | namespace cel::internal { |
28 | | namespace { |
29 | | |
30 | | constexpr int64_t kInt32Max = std::numeric_limits<int32_t>::max(); |
31 | | constexpr int64_t kInt32Min = std::numeric_limits<int32_t>::lowest(); |
32 | | constexpr int64_t kInt64Max = std::numeric_limits<int64_t>::max(); |
33 | | constexpr int64_t kInt64Min = std::numeric_limits<int64_t>::lowest(); |
34 | | constexpr uint64_t kUint32Max = std::numeric_limits<uint32_t>::max(); |
35 | | ABSL_ATTRIBUTE_UNUSED constexpr uint64_t kUint64Max = |
36 | | std::numeric_limits<uint64_t>::max(); |
37 | | constexpr uint64_t kUintToIntMax = static_cast<uint64_t>(kInt64Max); |
38 | | constexpr double kDoubleToIntMax = static_cast<double>(kInt64Max); |
39 | | constexpr double kDoubleToIntMin = static_cast<double>(kInt64Min); |
40 | | const double kDoubleTwoTo64 = std::ldexp(1.0, 64); // 1.0 * 2^64 |
41 | | |
42 | | const absl::Duration kOneSecondDuration = absl::Seconds(1); |
43 | | const int64_t kOneSecondNanos = absl::ToInt64Nanoseconds(kOneSecondDuration); |
44 | | // Number of seconds between `0001-01-01T00:00:00Z` and Unix epoch. |
45 | | const int64_t kMinUnixTime = |
46 | | absl::ToInt64Seconds(MinTimestamp() - absl::UnixEpoch()); |
47 | | |
48 | | // Number of seconds between `9999-12-31T23:59:59.999999999Z` and Unix epoch. |
49 | | const int64_t kMaxUnixTime = |
50 | | absl::ToInt64Seconds(MaxTimestamp() - absl::UnixEpoch()); |
51 | | |
52 | | absl::Status CheckRange(bool valid_expression, |
53 | 3.82k | absl::string_view error_message) { |
54 | 3.82k | return valid_expression ? absl::OkStatus() |
55 | 3.82k | : absl::OutOfRangeError(error_message); |
56 | 3.82k | } |
57 | | |
58 | | absl::Status CheckArgument(bool valid_expression, |
59 | 4.05k | absl::string_view error_message) { |
60 | 4.05k | return valid_expression ? absl::OkStatus() |
61 | 4.05k | : absl::InvalidArgumentError(error_message); |
62 | 4.05k | } |
63 | | |
64 | | // Determine whether the duration is finite. |
65 | 0 | bool IsFinite(absl::Duration d) { |
66 | 0 | return d != absl::InfiniteDuration() && d != -absl::InfiniteDuration(); |
67 | 0 | } |
68 | | |
69 | | // Determine whether the time is finite. |
70 | 0 | bool IsFinite(absl::Time t) { |
71 | 0 | return t != absl::InfiniteFuture() && t != absl::InfinitePast(); |
72 | 0 | } |
73 | | |
74 | | } // namespace |
75 | | |
76 | 491 | absl::StatusOr<int64_t> CheckedAdd(int64_t x, int64_t y) { |
77 | 491 | #if ABSL_HAVE_BUILTIN(__builtin_add_overflow) |
78 | 491 | int64_t sum; |
79 | 491 | if (!__builtin_add_overflow(x, y, &sum)) { |
80 | 455 | return sum; |
81 | 455 | } |
82 | 36 | return absl::OutOfRangeError("integer overflow"); |
83 | | #else |
84 | | CEL_RETURN_IF_ERROR(CheckRange( |
85 | | y > 0 ? x <= kInt64Max - y : x >= kInt64Min - y, "integer overflow")); |
86 | | return x + y; |
87 | | #endif |
88 | 491 | } |
89 | | |
90 | 4.16k | absl::StatusOr<int64_t> CheckedSub(int64_t x, int64_t y) { |
91 | 4.16k | #if ABSL_HAVE_BUILTIN(__builtin_sub_overflow) |
92 | 4.16k | int64_t diff; |
93 | 4.16k | if (!__builtin_sub_overflow(x, y, &diff)) { |
94 | 4.08k | return diff; |
95 | 4.08k | } |
96 | 72 | return absl::OutOfRangeError("integer overflow"); |
97 | | #else |
98 | | CEL_RETURN_IF_ERROR(CheckRange( |
99 | | y < 0 ? x <= kInt64Max + y : x >= kInt64Min + y, "integer overflow")); |
100 | | return x - y; |
101 | | #endif |
102 | 4.16k | } |
103 | | |
104 | 232 | absl::StatusOr<int64_t> CheckedNegation(int64_t v) { |
105 | 232 | #if ABSL_HAVE_BUILTIN(__builtin_mul_overflow) |
106 | 232 | int64_t prod; |
107 | 232 | if (!__builtin_mul_overflow(v, -1, &prod)) { |
108 | 232 | return prod; |
109 | 232 | } |
110 | 0 | return absl::OutOfRangeError("integer overflow"); |
111 | | #else |
112 | | CEL_RETURN_IF_ERROR(CheckRange(v != kInt64Min, "integer overflow")); |
113 | | return -v; |
114 | | #endif |
115 | 232 | } |
116 | | |
117 | 521 | absl::StatusOr<int64_t> CheckedMul(int64_t x, int64_t y) { |
118 | 521 | #if ABSL_HAVE_BUILTIN(__builtin_mul_overflow) |
119 | 521 | int64_t prod; |
120 | 521 | if (!__builtin_mul_overflow(x, y, &prod)) { |
121 | 429 | return prod; |
122 | 429 | } |
123 | 92 | return absl::OutOfRangeError("integer overflow"); |
124 | | #else |
125 | | CEL_RETURN_IF_ERROR( |
126 | | CheckRange(!((x == -1 && y == kInt64Min) || (y == -1 && x == kInt64Min) || |
127 | | (x > 0 && y > 0 && x > kInt64Max / y) || |
128 | | (x < 0 && y < 0 && x < kInt64Max / y) || |
129 | | // Avoid dividing kInt64Min by -1, use whichever value of x |
130 | | // or y is positive as the divisor. |
131 | | (x > 0 && y < 0 && y < kInt64Min / x) || |
132 | | (x < 0 && y > 0 && x < kInt64Min / y)), |
133 | | "integer overflow")); |
134 | | return x * y; |
135 | | #endif |
136 | 521 | } |
137 | | |
138 | 1.23k | absl::StatusOr<int64_t> CheckedDiv(int64_t x, int64_t y) { |
139 | 1.23k | CEL_RETURN_IF_ERROR( |
140 | 1.23k | CheckRange(x != kInt64Min || y != -1, "integer overflow")); |
141 | 1.23k | CEL_RETURN_IF_ERROR(CheckArgument(y != 0, "divide by zero")); |
142 | 944 | return x / y; |
143 | 1.20k | } |
144 | | |
145 | 2.00k | absl::StatusOr<int64_t> CheckedMod(int64_t x, int64_t y) { |
146 | 2.00k | CEL_RETURN_IF_ERROR( |
147 | 2.00k | CheckRange(x != kInt64Min || y != -1, "integer overflow")); |
148 | 2.00k | CEL_RETURN_IF_ERROR(CheckArgument(y != 0, "modulus by zero")); |
149 | 1.37k | return x % y; |
150 | 1.94k | } |
151 | | |
152 | 104 | absl::StatusOr<uint64_t> CheckedAdd(uint64_t x, uint64_t y) { |
153 | 104 | #if ABSL_HAVE_BUILTIN(__builtin_add_overflow) |
154 | 104 | uint64_t sum; |
155 | 104 | if (!__builtin_add_overflow(x, y, &sum)) { |
156 | 68 | return sum; |
157 | 68 | } |
158 | 36 | return absl::OutOfRangeError("unsigned integer overflow"); |
159 | | #else |
160 | | CEL_RETURN_IF_ERROR( |
161 | | CheckRange(x <= kUint64Max - y, "unsigned integer overflow")); |
162 | | return x + y; |
163 | | #endif |
164 | 104 | } |
165 | | |
166 | 347 | absl::StatusOr<uint64_t> CheckedSub(uint64_t x, uint64_t y) { |
167 | 347 | #if ABSL_HAVE_BUILTIN(__builtin_sub_overflow) |
168 | 347 | uint64_t diff; |
169 | 347 | if (!__builtin_sub_overflow(x, y, &diff)) { |
170 | 219 | return diff; |
171 | 219 | } |
172 | 128 | return absl::OutOfRangeError("unsigned integer overflow"); |
173 | | #else |
174 | | CEL_RETURN_IF_ERROR(CheckRange(y <= x, "unsigned integer overflow")); |
175 | | return x - y; |
176 | | #endif |
177 | 347 | } |
178 | | |
179 | 275 | absl::StatusOr<uint64_t> CheckedMul(uint64_t x, uint64_t y) { |
180 | 275 | #if ABSL_HAVE_BUILTIN(__builtin_mul_overflow) |
181 | 275 | uint64_t prod; |
182 | 275 | if (!__builtin_mul_overflow(x, y, &prod)) { |
183 | 206 | return prod; |
184 | 206 | } |
185 | 69 | return absl::OutOfRangeError("unsigned integer overflow"); |
186 | | #else |
187 | | CEL_RETURN_IF_ERROR( |
188 | | CheckRange(y == 0 || x <= kUint64Max / y, "unsigned integer overflow")); |
189 | | return x * y; |
190 | | #endif |
191 | 275 | } |
192 | | |
193 | 508 | absl::StatusOr<uint64_t> CheckedDiv(uint64_t x, uint64_t y) { |
194 | 508 | CEL_RETURN_IF_ERROR(CheckArgument(y != 0, "divide by zero")); |
195 | 261 | return x / y; |
196 | 508 | } |
197 | | |
198 | 393 | absl::StatusOr<uint64_t> CheckedMod(uint64_t x, uint64_t y) { |
199 | 393 | CEL_RETURN_IF_ERROR(CheckArgument(y != 0, "modulus by zero")); |
200 | 250 | return x % y; |
201 | 393 | } |
202 | | |
203 | 0 | absl::StatusOr<absl::Duration> CheckedAdd(absl::Duration x, absl::Duration y) { |
204 | 0 | CEL_RETURN_IF_ERROR( |
205 | 0 | CheckRange(IsFinite(x) && IsFinite(y), "integer overflow")); |
206 | | // absl::Duration can handle +- infinite durations, but the Go time.Duration |
207 | | // implementation caps the durations to those expressible within a single |
208 | | // int64 rather than (seconds int64, nanos int32). |
209 | | // |
210 | | // The absl implementation mirrors the protobuf implementation which supports |
211 | | // durations on the order of +- 10,000 years, but Go only supports +- 290 year |
212 | | // durations. |
213 | | // |
214 | | // Since Go is the more conservative of the implementations and 290 year |
215 | | // durations seem quite reasonable, this code mirrors the conservative |
216 | | // overflow behavior which would be observed in Go. |
217 | 0 | CEL_ASSIGN_OR_RETURN(int64_t nanos, CheckedAdd(absl::ToInt64Nanoseconds(x), |
218 | 0 | absl::ToInt64Nanoseconds(y))); |
219 | 0 | return absl::Nanoseconds(nanos); |
220 | 0 | } |
221 | | |
222 | 0 | absl::StatusOr<absl::Duration> CheckedSub(absl::Duration x, absl::Duration y) { |
223 | 0 | CEL_RETURN_IF_ERROR( |
224 | 0 | CheckRange(IsFinite(x) && IsFinite(y), "integer overflow")); |
225 | 0 | CEL_ASSIGN_OR_RETURN(int64_t nanos, CheckedSub(absl::ToInt64Nanoseconds(x), |
226 | 0 | absl::ToInt64Nanoseconds(y))); |
227 | 0 | return absl::Nanoseconds(nanos); |
228 | 0 | } |
229 | | |
230 | 0 | absl::StatusOr<absl::Duration> CheckedNegation(absl::Duration v) { |
231 | 0 | CEL_RETURN_IF_ERROR(CheckRange(IsFinite(v), "integer overflow")); |
232 | 0 | CEL_ASSIGN_OR_RETURN(int64_t nanos, |
233 | 0 | CheckedNegation(absl::ToInt64Nanoseconds(v))); |
234 | 0 | return absl::Nanoseconds(nanos); |
235 | 0 | } |
236 | | |
237 | 0 | absl::StatusOr<absl::Time> CheckedAdd(absl::Time t, absl::Duration d) { |
238 | 0 | CEL_RETURN_IF_ERROR( |
239 | 0 | CheckRange(IsFinite(t) && IsFinite(d), "timestamp overflow")); |
240 | | // First we break time into its components by truncating and subtracting. |
241 | 0 | const int64_t s1 = absl::ToUnixSeconds(t); |
242 | 0 | const int64_t ns1 = (t - absl::FromUnixSeconds(s1)) / absl::Nanoseconds(1); |
243 | | |
244 | | // Second we break duration into its components by dividing and modulo. |
245 | | // Truncate to seconds. |
246 | 0 | const int64_t s2 = d / kOneSecondDuration; |
247 | | // Get remainder. |
248 | 0 | const int64_t ns2 = absl::ToInt64Nanoseconds(d % kOneSecondDuration); |
249 | | |
250 | | // Add seconds first, detecting any overflow. |
251 | 0 | CEL_ASSIGN_OR_RETURN(int64_t s, CheckedAdd(s1, s2)); |
252 | | // Nanoseconds cannot overflow as nanos are normalized to [0, 999999999]. |
253 | 0 | absl::Duration ns = absl::Nanoseconds(ns2 + ns1); |
254 | | |
255 | | // Normalize nanoseconds to be positive and carry extra nanos to seconds. |
256 | 0 | if (ns < absl::ZeroDuration() || ns >= kOneSecondDuration) { |
257 | | // Add seconds, or no-op if nanseconds negative (ns never < -999_999_999ns) |
258 | 0 | CEL_ASSIGN_OR_RETURN(s, CheckedAdd(s, ns / kOneSecondDuration)); |
259 | 0 | ns -= (ns / kOneSecondDuration) * kOneSecondDuration; |
260 | | // Subtract a second to make the nanos positive. |
261 | 0 | if (ns < absl::ZeroDuration()) { |
262 | 0 | CEL_ASSIGN_OR_RETURN(s, CheckedAdd(s, -1)); |
263 | 0 | ns += kOneSecondDuration; |
264 | 0 | } |
265 | 0 | } |
266 | | // Check if the the number of seconds from Unix epoch is within our acceptable |
267 | | // range. |
268 | 0 | CEL_RETURN_IF_ERROR( |
269 | 0 | CheckRange(s >= kMinUnixTime && s <= kMaxUnixTime, "timestamp overflow")); |
270 | | |
271 | | // Return resulting time. |
272 | 0 | return absl::FromUnixSeconds(s) + ns; |
273 | 0 | } |
274 | | |
275 | 0 | absl::StatusOr<absl::Time> CheckedSub(absl::Time t, absl::Duration d) { |
276 | 0 | CEL_ASSIGN_OR_RETURN(auto neg_duration, CheckedNegation(d)); |
277 | 0 | return CheckedAdd(t, neg_duration); |
278 | 0 | } |
279 | | |
280 | 0 | absl::StatusOr<absl::Duration> CheckedSub(absl::Time t1, absl::Time t2) { |
281 | 0 | CEL_RETURN_IF_ERROR( |
282 | 0 | CheckRange(IsFinite(t1) && IsFinite(t2), "integer overflow")); |
283 | | // First we break time into its components by truncating and subtracting. |
284 | 0 | const int64_t s1 = absl::ToUnixSeconds(t1); |
285 | 0 | const int64_t ns1 = (t1 - absl::FromUnixSeconds(s1)) / absl::Nanoseconds(1); |
286 | 0 | const int64_t s2 = absl::ToUnixSeconds(t2); |
287 | 0 | const int64_t ns2 = (t2 - absl::FromUnixSeconds(s2)) / absl::Nanoseconds(1); |
288 | | |
289 | | // Subtract seconds first, detecting any overflow. |
290 | 0 | CEL_ASSIGN_OR_RETURN(int64_t s, CheckedSub(s1, s2)); |
291 | | // Nanoseconds cannot overflow as nanos are normalized to [0, 999999999]. |
292 | 0 | absl::Duration ns = absl::Nanoseconds(ns1 - ns2); |
293 | | |
294 | | // Scale the seconds result to nanos. |
295 | 0 | CEL_ASSIGN_OR_RETURN(const int64_t t, CheckedMul(s, kOneSecondNanos)); |
296 | | // Add the seconds (scaled to nanos) to the nanosecond value. |
297 | 0 | CEL_ASSIGN_OR_RETURN(const int64_t v, |
298 | 0 | CheckedAdd(t, absl::ToInt64Nanoseconds(ns))); |
299 | 0 | return absl::Nanoseconds(v); |
300 | 0 | } |
301 | | |
302 | 295 | absl::StatusOr<int64_t> CheckedDoubleToInt64(double v) { |
303 | 295 | CEL_RETURN_IF_ERROR( |
304 | 295 | CheckRange(std::isfinite(v) && v < kDoubleToIntMax && v > kDoubleToIntMin, |
305 | 295 | "double out of int64 range")); |
306 | 144 | return static_cast<int64_t>(v); |
307 | 295 | } |
308 | | |
309 | 33 | absl::StatusOr<uint64_t> CheckedDoubleToUint64(double v) { |
310 | 33 | CEL_RETURN_IF_ERROR( |
311 | 33 | CheckRange(std::isfinite(v) && v >= 0 && v < kDoubleTwoTo64, |
312 | 33 | "double out of uint64 range")); |
313 | 0 | return static_cast<uint64_t>(v); |
314 | 33 | } |
315 | | |
316 | 157 | absl::StatusOr<uint64_t> CheckedInt64ToUint64(int64_t v) { |
317 | 157 | CEL_RETURN_IF_ERROR(CheckRange(v >= 0, "int64 out of uint64 range")); |
318 | 65 | return static_cast<uint64_t>(v); |
319 | 157 | } |
320 | | |
321 | 0 | absl::StatusOr<int32_t> CheckedInt64ToInt32(int64_t v) { |
322 | 0 | CEL_RETURN_IF_ERROR( |
323 | 0 | CheckRange(v >= kInt32Min && v <= kInt32Max, "int64 out of int32 range")); |
324 | 0 | return static_cast<int32_t>(v); |
325 | 0 | } |
326 | | |
327 | 103 | absl::StatusOr<int64_t> CheckedUint64ToInt64(uint64_t v) { |
328 | 103 | CEL_RETURN_IF_ERROR( |
329 | 103 | CheckRange(v <= kUintToIntMax, "uint64 out of int64 range")); |
330 | 66 | return static_cast<int64_t>(v); |
331 | 103 | } |
332 | | |
333 | 0 | absl::StatusOr<uint32_t> CheckedUint64ToUint32(uint64_t v) { |
334 | 0 | CEL_RETURN_IF_ERROR( |
335 | 0 | CheckRange(v <= kUint32Max, "uint64 out of uint32 range")); |
336 | 0 | return static_cast<uint32_t>(v); |
337 | 0 | } |
338 | | |
339 | | } // namespace cel::internal |