about summary refs log tree commit diff
path: root/time
diff options
context:
space:
mode:
Diffstat (limited to 'time')
-rw-r--r--time/Makefile62
-rw-r--r--time/tst-clock_gettime-time64.c1
-rw-r--r--time/tst-clock_gettime.c184
-rw-r--r--time/tst-gettimeofday-time64.c1
-rw-r--r--time/tst-gettimeofday.c93
-rw-r--r--time/tst-time-time64.c1
-rw-r--r--time/tst-time.c51
-rw-r--r--time/tst-tzfile-fault.c44
-rw-r--r--time/tzfile.c5
9 files changed, 431 insertions, 11 deletions
diff --git a/time/Makefile b/time/Makefile
index 5b541fb9d3..4bfb208110 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -42,30 +42,70 @@ routines := offtime asctime clock ctime ctime_r difftime \
 
 aux :=	    era alt_digit lc-time-cleanup
 
-tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
-	   tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
-	   tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
-	   tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-ftime \
-	   tst-tzname tst-y2039 bug-mktime4 tst-strftime2 tst-strftime3 \
-	   tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \
-	   tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \
-	   tst-settimeofday tst-itimer tst-gmtime tst-timegm \
-	   tst-timespec_get tst-timespec_getres tst-strftime4
+tests := \
+  bug-asctime \
+  bug-asctime_r \
+  bug-getdate1 \
+  bug-mktime1 \
+  bug-mktime4 \
+  clocktest \
+  test_time \
+  tst-adjtime \
+  tst-clock \
+  tst-clock2 \
+  tst-clock_gettime \
+  tst-clock_nanosleep \
+  tst-clock_settime \
+  tst-cpuclock1 \
+  tst-ctime \
+  tst-difftime \
+  tst-ftime \
+  tst-ftime_l \
+  tst-getdate \
+  tst-gettimeofday \
+  tst-gmtime \
+  tst-itimer \
+  tst-mktime \
+  tst-mktime2 \
+  tst-mktime3 \
+  tst-mktime4 \
+  tst-posixtz \
+  tst-settimeofday \
+  tst-strftime \
+  tst-strftime2 \
+  tst-strftime3 \
+  tst-strftime4 \
+  tst-strptime \
+  tst-strptime-whitespace \
+  tst-strptime2 \
+  tst-strptime3 \
+  tst-time \
+  tst-timegm \
+  tst-timespec_get \
+  tst-timespec_getres \
+  tst-tzfile-fault \
+  tst-tzname \
+  tst-y2039 \
+  tst_wcsftime \
+  # tests
 
 tests-time64 := \
   tst-adjtime-time64 \
   tst-clock-time64 \
   tst-clock2-time64 \
+  tst-clock_gettime-time64 \
   tst-clock_nanosleep-time64 \
   tst-clock_settime-time64 \
   tst-cpuclock1-time64 \
   tst-ctime-time64 \
   tst-difftime-time64 \
+  tst-gettimeofday-time64 \
   tst-gmtime-time64 \
   tst-itimer-time64 \
   tst-mktime4-time64 \
   tst-settimeofday-time64 \
   tst-strftime4-time64 \
+  tst-time-time64 \
   tst-timegm-time64 \
   tst-timespec_get-time64 \
   tst-timespec_getres-time64 \
@@ -87,6 +127,8 @@ $(objpfx)tst-strftime2.out: $(gen-locales)
 $(objpfx)tst-strftime3.out: $(gen-locales)
 endif
 
+$(objpfx)tst-clock_gettime: $(librt)
+$(objpfx)tst-clock_gettime-time64: $(librt)
 $(objpfx)tst-clock_nanosleep: $(librt)
 $(objpfx)tst-clock_nanosleep-time64: $(librt)
 
@@ -110,3 +152,5 @@ tst-tzname-ENV = TZDIR=${common-objpfx}timezone/testdata
 CPPFLAGS-tst-tzname.c += -DTZDEFRULES='"$(posixrules-file)"'
 
 bug-getdate1-ARGS = ${objpfx}bug-getdate1-fmt
+
+tst-tzfile-fault-ENV = GLIBC_TUNABLES=glibc.rtld.enable_secure=1
diff --git a/time/tst-clock_gettime-time64.c b/time/tst-clock_gettime-time64.c
new file mode 100644
index 0000000000..5b215d11f8
--- /dev/null
+++ b/time/tst-clock_gettime-time64.c
@@ -0,0 +1 @@
+#include "tst-clock_gettime.c"
diff --git a/time/tst-clock_gettime.c b/time/tst-clock_gettime.c
new file mode 100644
index 0000000000..51f24c0be2
--- /dev/null
+++ b/time/tst-clock_gettime.c
@@ -0,0 +1,184 @@
+/* Test clock_gettime function.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <support/xsignal.h>
+
+/* Compare two struct timespec values, returning a value -1, 0 or 1.  */
+
+int
+compare_timespec (const struct timespec *tv1, const struct timespec *tv2)
+{
+  if (tv1->tv_sec < tv2->tv_sec)
+    return -1;
+  if (tv1->tv_sec > tv2->tv_sec)
+    return 1;
+  if (tv1->tv_nsec < tv2->tv_nsec)
+    return -1;
+  if (tv1->tv_nsec > tv2->tv_nsec)
+    return 1;
+  return 0;
+}
+
+struct test_clockid
+{
+  clockid_t clockid;
+  const char *name;
+  bool is_cputime;
+  bool fail_ok;
+};
+
+#define CLOCK(clockid) { clockid, # clockid, false, false }
+#define CLOCK_CPU(clockid) { clockid, # clockid, true, false }
+#define CLOCK_FAIL_OK(clockid) { clockid, # clockid, false, true }
+
+static const struct test_clockid clocks[] =
+  {
+    CLOCK (CLOCK_REALTIME),
+#ifdef CLOCK_MONOTONIC
+    CLOCK (CLOCK_MONOTONIC),
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+    CLOCK_CPU (CLOCK_PROCESS_CPUTIME_ID),
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+    CLOCK_CPU (CLOCK_THREAD_CPUTIME_ID),
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+    CLOCK (CLOCK_MONOTONIC_RAW),
+#endif
+#ifdef CLOCK_REALTIME_COARSE
+    CLOCK (CLOCK_REALTIME_COARSE),
+#endif
+#ifdef CLOCK_MONOTONIC_COARSE
+    CLOCK (CLOCK_MONOTONIC_COARSE),
+#endif
+#ifdef CLOCK_BOOTTIME
+    CLOCK (CLOCK_BOOTTIME),
+#endif
+#ifdef CLOCK_REALTIME_ALARM
+    CLOCK_FAIL_OK (CLOCK_REALTIME_ALARM),
+#endif
+#ifdef CLOCK_BOOTTIME_ALARM
+    CLOCK_FAIL_OK (CLOCK_BOOTTIME_ALARM),
+#endif
+#ifdef CLOCK_TAI
+    CLOCK (CLOCK_TAI),
+#endif
+  };
+
+
+volatile int sigalrm_received;
+
+void
+handle_sigalrm (int sig)
+{
+  sigalrm_received = 1;
+}
+
+int
+do_test (void)
+{
+  /* Verify that the calls to clock_gettime succeed, that the time does
+     not decrease, and that time returns a truncated (not rounded)
+     version of the time.  */
+  for (size_t i = 0; i < sizeof clocks / sizeof clocks[0]; i++)
+    {
+      printf ("testing %s\n", clocks[i].name);
+      struct timespec ts1, ts2, ts3;
+      int ret;
+      time_t t1;
+      t1 = time (NULL);
+      TEST_VERIFY_EXIT (t1 != (time_t) -1);
+      ret = clock_gettime (clocks[i].clockid, &ts1);
+      if (clocks[i].fail_ok && ret == -1)
+	{
+	  printf ("failed (OK for this clock): %m\n");
+	  continue;
+	}
+      TEST_VERIFY_EXIT (ret == 0);
+      if (clocks[i].clockid == CLOCK_REALTIME)
+	TEST_VERIFY (t1 <= ts1.tv_sec);
+      TEST_VERIFY (ts1.tv_nsec >= 0);
+      TEST_VERIFY (ts1.tv_nsec < 1000000000);
+      ret = clock_gettime (clocks[i].clockid, &ts2);
+      TEST_VERIFY_EXIT (ret == 0);
+      TEST_VERIFY (compare_timespec (&ts1, &ts2) <= 0);
+      TEST_VERIFY (ts2.tv_nsec >= 0);
+      TEST_VERIFY (ts2.tv_nsec < 1000000000);
+      /* Also verify that after sleeping, the time returned has
+	 increased.  Repeat several times to verify that each time,
+	 the time from the time function is truncated not rounded.
+	 For CPU time clocks, the time spent spinning on the CPU, and
+	 so whether we end in the later half of a second, is not
+	 predictable; thus, only test once for those clocks.  */
+      const struct timespec duration = { .tv_nsec = 100000000 };
+      for (int j = 0; j < 5; j++)
+	{
+	  if (clocks[i].is_cputime)
+	    {
+	      timer_t timer;
+	      ret = timer_create (CLOCK_PROCESS_CPUTIME_ID, NULL, &timer);
+	      TEST_VERIFY_EXIT (ret == 0);
+	      sigalrm_received = 0;
+	      xsignal (SIGALRM, handle_sigalrm);
+	      struct itimerspec t =
+		{ .it_value =
+		  {
+		    .tv_sec = 0,
+		    .tv_nsec = 200000000
+		  }
+		};
+	      ret = timer_settime (timer, 0, &t, NULL);
+	      TEST_VERIFY_EXIT (ret == 0);
+	      while (sigalrm_received == 0)
+		;
+	      xsignal (SIGALRM, SIG_DFL);
+	      ret = timer_delete (timer);
+	      TEST_VERIFY_EXIT (ret == 0);
+	    }
+	  else
+	    {
+	      ret = nanosleep (&duration, NULL);
+	      TEST_VERIFY_EXIT (ret == 0);
+	    }
+	  t1 = time (NULL);
+	  TEST_VERIFY_EXIT (t1 != (time_t) -1);
+	  ret = clock_gettime (clocks[i].clockid, &ts3);
+	  TEST_VERIFY_EXIT (ret == 0);
+	  TEST_VERIFY (compare_timespec (&ts2, &ts3) < 0);
+	  if (clocks[i].clockid == CLOCK_REALTIME)
+	    TEST_VERIFY (t1 <= ts3.tv_sec);
+	  TEST_VERIFY (ts3.tv_nsec >= 0);
+	  TEST_VERIFY (ts3.tv_nsec < 1000000000);
+	  ts2 = ts3;
+	  if (clocks[i].is_cputime)
+	    break;
+	}
+    }
+  return 0;
+}
+
+#define TIMEOUT 60
+
+#include <support/test-driver.c>
diff --git a/time/tst-gettimeofday-time64.c b/time/tst-gettimeofday-time64.c
new file mode 100644
index 0000000000..6c08761ef9
--- /dev/null
+++ b/time/tst-gettimeofday-time64.c
@@ -0,0 +1 @@
+#include "tst-gettimeofday.c"
diff --git a/time/tst-gettimeofday.c b/time/tst-gettimeofday.c
new file mode 100644
index 0000000000..978ae28587
--- /dev/null
+++ b/time/tst-gettimeofday.c
@@ -0,0 +1,93 @@
+/* Test gettimeofday function.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/time.h>
+#include <time.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+/* Compare two struct timeval values, returning a value -1, 0 or 1.  */
+
+int
+compare_timeval (const struct timeval *tv1, const struct timeval *tv2)
+{
+  if (tv1->tv_sec < tv2->tv_sec)
+    return -1;
+  if (tv1->tv_sec > tv2->tv_sec)
+    return 1;
+  if (tv1->tv_usec < tv2->tv_usec)
+    return -1;
+  if (tv1->tv_usec > tv2->tv_usec)
+    return 1;
+  return 0;
+}
+
+int
+do_test (void)
+{
+  struct timeval tv1, tv2, tv3;
+  int ret;
+  time_t t1;
+  /* Verify that the calls to gettimeofday succeed, that the time does
+     not decrease, and that time returns a truncated (not rounded)
+     version of the time.  */
+  t1 = time (NULL);
+  TEST_VERIFY_EXIT (t1 != (time_t) -1);
+  ret = gettimeofday (&tv1, NULL);
+  TEST_VERIFY_EXIT (ret == 0);
+  TEST_VERIFY (t1 <= tv1.tv_sec);
+  TEST_VERIFY (tv1.tv_usec >= 0);
+  TEST_VERIFY (tv1.tv_usec < 1000000);
+  ret = gettimeofday (&tv2, NULL);
+  TEST_VERIFY_EXIT (ret == 0);
+  TEST_VERIFY (compare_timeval (&tv1, &tv2) <= 0);
+  TEST_VERIFY (tv2.tv_usec >= 0);
+  TEST_VERIFY (tv2.tv_usec < 1000000);
+  /* Also verify that after sleeping, the time returned has increased.
+     Repeat several times to verify that each time, the time from the
+     time function is truncated not rounded.  */
+  const struct timespec duration = { .tv_nsec = 100000000 };
+  for (int i = 0; i < 10; i++)
+    {
+      ret = nanosleep (&duration, NULL);
+      TEST_VERIFY_EXIT (ret == 0);
+      t1 = time (NULL);
+      TEST_VERIFY_EXIT (t1 != (time_t) -1);
+      ret = gettimeofday (&tv3, NULL);
+      TEST_VERIFY_EXIT (ret == 0);
+      TEST_VERIFY (compare_timeval (&tv2, &tv3) < 0);
+      TEST_VERIFY (t1 <= tv3.tv_sec);
+      TEST_VERIFY (tv3.tv_usec >= 0);
+      TEST_VERIFY (tv3.tv_usec < 1000000);
+      tv2 = tv3;
+    }
+  /* Also test with the obsolete tz argument not being NULL.  */
+  struct timezone tz = { 0 };
+  t1 = time (NULL);
+  TEST_VERIFY_EXIT (t1 != (time_t) -1);
+  ret = gettimeofday (&tv3, &tz);
+  TEST_VERIFY_EXIT (ret == 0);
+  TEST_VERIFY (t1 <= tv3.tv_sec);
+  TEST_VERIFY (compare_timeval (&tv2, &tv3) <= 0);
+  TEST_VERIFY (tv3.tv_usec >= 0);
+  TEST_VERIFY (tv3.tv_usec < 1000000);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/time/tst-time-time64.c b/time/tst-time-time64.c
new file mode 100644
index 0000000000..30e8d3c86e
--- /dev/null
+++ b/time/tst-time-time64.c
@@ -0,0 +1 @@
+#include "tst-time.c"
diff --git a/time/tst-time.c b/time/tst-time.c
new file mode 100644
index 0000000000..7f24bed353
--- /dev/null
+++ b/time/tst-time.c
@@ -0,0 +1,51 @@
+/* Test time function.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <time.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+int
+do_test (void)
+{
+  time_t t1, t2, t3, t4, t5, t6;
+  /* Verify that the calls to time succeed, that the value returned
+     directly equals that returned through the pointer passed, and
+     that the time does not decrease.  */
+  t1 = time (&t2);
+  TEST_VERIFY_EXIT (t1 != (time_t) -1);
+  TEST_VERIFY (t1 == t2);
+  t3 = time (NULL);
+  TEST_VERIFY_EXIT (t3 != (time_t) -1);
+  TEST_VERIFY (t3 >= t1);
+  /* Also verify that after sleeping, the time returned has
+     increased.  */
+  sleep (2);
+  t4 = time (&t5);
+  TEST_VERIFY_EXIT (t4 != (time_t) -1);
+  TEST_VERIFY (t4 == t5);
+  TEST_VERIFY (t4 > t3);
+  t6 = time (NULL);
+  TEST_VERIFY_EXIT (t6 != (time_t) -1);
+  TEST_VERIFY (t6 >= t4);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/time/tst-tzfile-fault.c b/time/tst-tzfile-fault.c
new file mode 100644
index 0000000000..105c2ac7ce
--- /dev/null
+++ b/time/tst-tzfile-fault.c
@@ -0,0 +1,44 @@
+/* Attempt to trigger fault with very short TZ variable (bug 31931).
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+
+#include <support/next_to_fault.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+static char tz[] = "TZ=/";
+
+static int
+do_test (void)
+{
+  struct support_next_to_fault ntf
+    = support_next_to_fault_allocate (sizeof (tz));
+  memcpy (ntf.buffer, tz, sizeof (tz));
+  putenv (ntf.buffer);
+
+  tzset ();
+
+  /* Avoid dangling pointer in environ.  */
+  putenv (tz);
+  support_next_to_fault_free (&ntf);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/time/tzfile.c b/time/tzfile.c
index 4147539964..964a9b7f12 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -134,8 +134,9 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
 	 and which is not the system wide default TZDEFAULT.  */
       if (__libc_enable_secure
 	  && ((*file == '/'
-	       && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
-	       && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
+	       && strcmp (file, TZDEFAULT) != 0
+	       && (strncmp (file, default_tzdir, sizeof (default_tzdir) - 1)
+		   != 0))
 	      || strstr (file, "../") != NULL))
 	/* This test is certainly a bit too restrictive but it should
 	   catch all critical cases.  */