[glib/glib-2-70: 1/2] gtimezone: Fix assertion failure when called with a huge offset




commit 0b63312775c032b64fe3799b6bb5e464fbcdf0f1
Author: Philip Withnall <pwithnall endlessos org>
Date:   Wed Mar 16 12:47:03 2022 +0000

    gtimezone: Fix assertion failure when called with a huge offset
    
    This looks like a regression from commit 3356934db5, but prior to that
    commit there was always an assertion failure when calling
    `g_time_zone_new_offset()` with an offset which is too large (such as 44
    hours), ever since the function was added in commit cf24867b93.
    
    It would be ideal if we could return a `NULL` timezone to indicate the
    error, but that’s not part of the API for `g_time_zone_new_offset()`, so
    we have to go with the dated and not-ideal approach of returning the UTC
    timezone and letting the caller figure it out.
    
    Another potential approach would be to reduce the `offset` modulo 24
    hours. This makes the error less easily detectable than if returning
    UTC, though, and still returns an invalid result: `+44:00` is not the
    same timezone as `+20:00` (it’s one day further ahead).
    
    Add a unit test.
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>
    
    Fixes: #2620

 glib/gtimezone.c       | 16 +++++++++++++---
 glib/tests/gdatetime.c | 48 ++++++++++++++++++++++++++++++++----------------
 2 files changed, 45 insertions(+), 19 deletions(-)
---
diff --git a/glib/gtimezone.c b/glib/gtimezone.c
index 4b4324222..df7147869 100644
--- a/glib/gtimezone.c
+++ b/glib/gtimezone.c
@@ -1937,7 +1937,13 @@ g_time_zone_new_local (void)
  * This is equivalent to calling g_time_zone_new() with a string in the form
  * `[+|-]hh[:mm[:ss]]`.
  *
- * Returns: (transfer full): a timezone at the given offset from UTC
+ * It is possible for this function to fail if @seconds is too big (greater than
+ * 24 hours), in which case this function will return the UTC timezone for
+ * backwards compatibility. To detect failures like this, use
+ * g_time_zone_new_identifier() directly.
+ *
+ * Returns: (transfer full): a timezone at the given offset from UTC, or UTC on
+ *   failure
  * Since: 2.58
  */
 GTimeZone *
@@ -1957,11 +1963,15 @@ g_time_zone_new_offset (gint32 seconds)
                                 (ABS (seconds) / 60) % 60,
                                 ABS (seconds) % 60);
   tz = g_time_zone_new_identifier (identifier);
+
+  if (tz == NULL)
+    tz = g_time_zone_new_utc ();
+  else
+    g_assert (g_time_zone_get_offset (tz, 0) == seconds);
+
   g_assert (tz != NULL);
   g_free (identifier);
 
-  g_assert (g_time_zone_get_offset (tz, 0) == seconds);
-
   return tz;
 }
 
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index 12f332b44..38555bfeb 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -2916,19 +2916,26 @@ test_identifier (void)
 static void
 test_new_offset (void)
 {
-  const gint32 vectors[] =
+  const struct
     {
-      -10000,
-      -3600,
-      -61,
-      -60,
-      -59,
-      0,
-      59,
-      60,
-      61,
-      3600,
-      10000,
+      gint32 offset;
+      gboolean expected_success;
+    }
+  vectors[] =
+    {
+      { -158400, FALSE },
+      { -10000, TRUE },
+      { -3600, TRUE },
+      { -61, TRUE },
+      { -60, TRUE },
+      { -59, TRUE },
+      { 0, TRUE },
+      { 59, TRUE },
+      { 60, TRUE },
+      { 61, TRUE },
+      { 3600, TRUE },
+      { 10000, TRUE },
+      { 158400, FALSE },
     };
   gsize i;
 
@@ -2936,12 +2943,21 @@ test_new_offset (void)
     {
       GTimeZone *tz = NULL;
 
-      g_test_message ("Vector %" G_GSIZE_FORMAT ": %d", i, vectors[i]);
+      g_test_message ("Vector %" G_GSIZE_FORMAT ": %d", i, vectors[i].offset);
 
-      tz = g_time_zone_new_offset (vectors[i]);
+      tz = g_time_zone_new_offset (vectors[i].offset);
       g_assert_nonnull (tz);
-      g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "UTC");
-      g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, vectors[i]);
+
+      if (vectors[i].expected_success)
+        {
+          g_assert_cmpstr (g_time_zone_get_identifier (tz), !=, "UTC");
+          g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, vectors[i].offset);
+        }
+      else
+        {
+          g_assert_cmpstr (g_time_zone_get_identifier (tz), ==, "UTC");
+        }
+
       g_time_zone_unref (tz);
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]