Skip to content

Commit 80225af

Browse files
[libc] Fix overflow check for 32 bit long time_t (#65394)
This patch fixes the overflow check in update_from_seconds, used by gmtime, gmtime_r and mktime. In update_from_seconds, total_seconds is a int64_t and the previous overflow check for when sizeof(time_t) == 4 would check if it was < 0x80000000 and > 0x7FFFFFFF, however, this check would cause the following issues: 1. Valid negative numbers would be discarded, e.g., -1 is 0xffffffffffffffff as a int64_t, outside the range of the overflow check. 2. Some valid positive numbers would be discarded because the hex constants were being implicitly converted to int64_t, e.g., 0x80000000 would be implicitly converted to 2147483648, instead of -2147483648. The fix for both cases was to static_cast total_seconds and the constants to time_t if sizeof(time_t) == 4. The behaviour is not changed in systems with sizeof(time_t) == 8. --------- Signed-off-by: Mikhail R. Gadelha <[email protected]>
1 parent 281ae49 commit 80225af

File tree

3 files changed

+18
-18
lines changed

3 files changed

+18
-18
lines changed

libc/src/time/mktime.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ LLVM_LIBC_FUNCTION(time_t, mktime, (struct tm * tm_out)) {
5353

5454
// Years are ints. A 32-bit year will fit into a 64-bit time_t.
5555
// A 64-bit year will not.
56-
static_assert(sizeof(int) == 4,
57-
"ILP64 is unimplemented. This implementation requires "
58-
"32-bit integers.");
56+
static_assert(
57+
sizeof(int) == 4,
58+
"ILP64 is unimplemented. This implementation requires 32-bit integers.");
5959

6060
// Calculate number of months and years from tm_mon.
6161
int64_t month = tm_out->tm_mon;

libc/src/time/time_utils.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,20 @@ int64_t update_from_seconds(int64_t total_seconds, struct tm *tm) {
4848
static const char daysInMonth[] = {31 /* Mar */, 30, 31, 30, 31, 31,
4949
30, 31, 30, 31, 31, 29};
5050

51-
if (sizeof(time_t) == 4) {
52-
if (total_seconds < 0x80000000)
53-
return time_utils::out_of_range();
54-
if (total_seconds > 0x7FFFFFFF)
55-
return time_utils::out_of_range();
56-
} else {
57-
if (total_seconds <
58-
INT_MIN * static_cast<int64_t>(
59-
TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR) ||
60-
total_seconds >
61-
INT_MAX * static_cast<int64_t>(
62-
TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR))
63-
return time_utils::out_of_range();
64-
}
51+
constexpr time_t time_min =
52+
(sizeof(time_t) == 4)
53+
? INT_MIN
54+
: INT_MIN * static_cast<int64_t>(
55+
TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR);
56+
constexpr time_t time_max =
57+
(sizeof(time_t) == 4)
58+
? INT_MAX
59+
: INT_MAX * static_cast<int64_t>(
60+
TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR);
61+
62+
time_t ts = static_cast<time_t>(total_seconds);
63+
if (ts < time_min || ts > time_max)
64+
return time_utils::out_of_range();
6565

6666
int64_t seconds =
6767
total_seconds - TimeConstants::SECONDS_UNTIL2000_MARCH_FIRST;

libc/src/time/time_utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ extern int64_t update_from_seconds(int64_t total_seconds, struct tm *tm);
9292
// POSIX.1-2017 requires this.
9393
LIBC_INLINE time_t out_of_range() {
9494
libc_errno = EOVERFLOW;
95-
return static_cast<time_t>(-1);
95+
return TimeConstants::OUT_OF_RANGE_RETURN_VALUE;
9696
}
9797

9898
LIBC_INLINE void invalid_value() { libc_errno = EINVAL; }

0 commit comments

Comments
 (0)