[libc-commits] [libc] 80225af - [libc] Fix overflow check for 32 bit long time_t (#65394)

via libc-commits libc-commits at lists.llvm.org
Thu Sep 7 06:18:28 PDT 2023


Author: Mikhail R. Gadelha
Date: 2023-09-07T09:18:23-04:00
New Revision: 80225af4c1445c7818c6a71121d83bcc8ed7dd3b

URL: https://github.com/llvm/llvm-project/commit/80225af4c1445c7818c6a71121d83bcc8ed7dd3b
DIFF: https://github.com/llvm/llvm-project/commit/80225af4c1445c7818c6a71121d83bcc8ed7dd3b.diff

LOG: [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 <mikhail at igalia.com>

Added: 
    

Modified: 
    libc/src/time/mktime.cpp
    libc/src/time/time_utils.cpp
    libc/src/time/time_utils.h

Removed: 
    


################################################################################
diff  --git a/libc/src/time/mktime.cpp b/libc/src/time/mktime.cpp
index ea748ce4ab72737..3b3ea339f850f96 100644
--- a/libc/src/time/mktime.cpp
+++ b/libc/src/time/mktime.cpp
@@ -53,9 +53,9 @@ LLVM_LIBC_FUNCTION(time_t, mktime, (struct tm * tm_out)) {
 
   // Years are ints.  A 32-bit year will fit into a 64-bit time_t.
   // A 64-bit year will not.
-  static_assert(sizeof(int) == 4,
-                "ILP64 is unimplemented.  This implementation requires "
-                "32-bit integers.");
+  static_assert(
+      sizeof(int) == 4,
+      "ILP64 is unimplemented. This implementation requires 32-bit integers.");
 
   // Calculate number of months and years from tm_mon.
   int64_t month = tm_out->tm_mon;

diff  --git a/libc/src/time/time_utils.cpp b/libc/src/time/time_utils.cpp
index 2cb0f071e6ce111..fadd26f97dfc228 100644
--- a/libc/src/time/time_utils.cpp
+++ b/libc/src/time/time_utils.cpp
@@ -48,20 +48,20 @@ int64_t update_from_seconds(int64_t total_seconds, struct tm *tm) {
   static const char daysInMonth[] = {31 /* Mar */, 30, 31, 30, 31, 31,
                                      30,           31, 30, 31, 31, 29};
 
-  if (sizeof(time_t) == 4) {
-    if (total_seconds < 0x80000000)
-      return time_utils::out_of_range();
-    if (total_seconds > 0x7FFFFFFF)
-      return time_utils::out_of_range();
-  } else {
-    if (total_seconds <
-            INT_MIN * static_cast<int64_t>(
-                          TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR) ||
-        total_seconds >
-            INT_MAX * static_cast<int64_t>(
-                          TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR))
-      return time_utils::out_of_range();
-  }
+  constexpr time_t time_min =
+      (sizeof(time_t) == 4)
+          ? INT_MIN
+          : INT_MIN * static_cast<int64_t>(
+                          TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR);
+  constexpr time_t time_max =
+      (sizeof(time_t) == 4)
+          ? INT_MAX
+          : INT_MAX * static_cast<int64_t>(
+                          TimeConstants::NUMBER_OF_SECONDS_IN_LEAP_YEAR);
+
+  time_t ts = static_cast<time_t>(total_seconds);
+  if (ts < time_min || ts > time_max)
+    return time_utils::out_of_range();
 
   int64_t seconds =
       total_seconds - TimeConstants::SECONDS_UNTIL2000_MARCH_FIRST;

diff  --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 8075bfe32027ae6..424e7521504d917 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -92,7 +92,7 @@ extern int64_t update_from_seconds(int64_t total_seconds, struct tm *tm);
 // POSIX.1-2017 requires this.
 LIBC_INLINE time_t out_of_range() {
   libc_errno = EOVERFLOW;
-  return static_cast<time_t>(-1);
+  return TimeConstants::OUT_OF_RANGE_RETURN_VALUE;
 }
 
 LIBC_INLINE void invalid_value() { libc_errno = EINVAL; }


        


More information about the libc-commits mailing list