Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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