Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Jan 2021 21:19:44 +0100
From:      Walter von Entferndt <walter.von.entferndt@posteo.net>
To:        Mark Millard <marklmi@yahoo.com>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Implicit assumptions (was: Re: Some fun with -O2)
Message-ID:  <1648904.MsCH1bHPGx@t450s.local.lan>
In-Reply-To: <7623BADF-5FA9-4712-8D85-A1D2B82E3F74@yahoo.com>
References:  <mailman.29.1610625600.45116.freebsd-hackers@freebsd.org> <1725854.nNRVL2rNYg@t450s.local.lan> <7623BADF-5FA9-4712-8D85-A1D2B82E3F74@yahoo.com>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

--nextPart1974885.4WAli8B44Z
Content-Transfer-Encoding: 7Bit
Content-Type: text/plain; charset="us-ascii"

At Samstag, 16. Januar 2021, 11:23:03 CET, Mark Millard wrote:
> This is the sort of thing where FreeBSD and Linux use a C subset
> for the specific issue, as defined by POSIX.1-2017/"The Open Group
> Base Specifications" Issue 7, 2018 edition/IEEE STd 1003-2017/... .
> For example:
> 
> https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html
> 
> reports (in its own terminology that may not be a full match to C's):
> 
> QUOTE
> clock_t shall be an integer or real-floating type. time_t shall be an
> integer type. END QUOTE
> 
> Limiting to such a time_t is easier to cover. [...]
> Restricting time_t to integer types leaves a compatible context.
> So: no "conflict" in that respect.
> 
My understanding is that check_mktime.c is a test program called by autoconf 
or such, designed to run on various UNIX platforms?  I mean it does not only 
need to run on BSD & Linux.
Maybe something like this will cover the most cases in practice:
--- check_mktime.c.patch ---
--- check_mktime.c.orig	2021-01-15 03:19:33.962253000 +0100
+++ check_mktime.c	2021-01-16 21:00:36.160616000 +0100
@@ -3,6 +3,13 @@
 # include <sys/time.h>
 # include <time.h>
 # include <unistd.h>
+# include <stdlib.h>
+#include <stdint.h>
+# include <stdio.h>	/* printf() */
+# include <limits.h>	/* CHAR_BIT */
+#if 0
+# include <inttypes.h>	/* format spec PRIX64: ll/l + X on 32/64-bit arch */
+#endif
 
 /* Work around redefinition to rpl_putenv by other config tests.  */
 #undef putenv
@@ -16,6 +23,78 @@
 };
 #define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0]))
 
+/* Count the bits set in any unsigned integer type.
+ * Returns the precision (width - padding bits - sign bit) iff given
+ * the xxx_MAX value of any integer type, signed or unsigned.
+ * From SEI CERT C Coding Standard:
+ * Rules for Developing Safe, Reliable, and Secure Systems (2016)
+ */
+size_t
+popcount (num)
+uintmax_t num;
+{
+  size_t cnt = 0;
+    
+  while (num != 0)
+    {
+      if (num % 2 == 1)
+      cnt++;
+      num >>= 1;
+    }
+  return cnt;
+}
+#define PRECISION(max_value) popcount(max_value)
+
+/* Guess the maximum value of a time_t from it's storage width.
+ * ASSERT time_t is not a floating point, or of any arcane width, or 
unsigned.
+ * Only 4...8 byte width of a time_t are tested.
+ * On error: returns (time_t)(-1)
+ */
+time_t
+guess_time_t_max ()
+{
+  time_t t0, t1 = (time_t)(-1);
+  size_t size, prec;
+
+  switch ((size = sizeof(time_t)))
+    {
+      case 4:
+	prec = PRECISION((time_t) 0xFFFFFFFF);
+	break;
+      case 5:
+	prec = PRECISION((time_t) 0xFFFFFFFFFF);
+	break;
+      case 6:
+	prec = PRECISION((time_t) 0xFFFFFFFFFFFF);
+	break;
+      case 7:
+	prec = PRECISION((time_t) 0xFFFFFFFFFFFFFF);
+	break;
+      case 8:
+	prec = PRECISION((time_t) 0xFFFFFFFFFFFFFFFF);
+	break;
+      default:
+	prec = 1;
+	break;
+    }
+  prec--; /* assumption: time_t is signed */
+  if (prec)
+    {
+      t0 = (time_t) 1 << (prec - 1);
+      t1 = t0|(t0 - 1);
+    }
+
+  /* FIXME not portable: time_t can be floating point type,
+   * or another integer type other than long or long long.
+   *
+  fprintf (stderr, "time_t_max\t= 0x%"PRIX64"\n", t1);*/
+  fprintf (stderr, "sizeof(time_t)\t= %2zd byte\n", size);
+  fprintf (stderr, "precision\t= %2zd bit\n", prec);
+  fprintf (stderr, "padding\t\t= %2zd bit\n", size*CHAR_BIT - prec - 1 /* 
sign */);
+
+  return t1;
+}
+
 /* Fail if mktime fails to convert a date in the spring-forward gap.
    Based on a problem report from Andreas Jaeger.  */
 static void
@@ -106,9 +185,7 @@
   time_t t, delta;
   int i, j;
 
-  for (time_t_max = 1; 0 < time_t_max; time_t_max *= 2)
-    continue;
-  time_t_max--;
+  time_t_max = guess_time_t_max ();
   delta = time_t_max / 997; /* a suitable prime number */
   for (i = 0; i < N_STRINGS; i++)
     {
@@ -128,3 +205,4 @@
   spring_forward_gap ();
   exit (0);
 }
+/*! vi: set ai tabstop=8 shiftwidth=2: */

---
-- 
=|o)	"Stell' Dir vor es geht und keiner kriegt's hin." (Wolfgang Neuss)
--nextPart1974885.4WAli8B44Z
Content-Disposition: attachment; filename="check_mktime.c.patch"
Content-Transfer-Encoding: 7Bit
Content-Type: text/x-patch; charset="UTF-8"; name="check_mktime.c.patch"

--- check_mktime.c.orig	2021-01-15 03:19:33.962253000 +0100
+++ check_mktime.c	2021-01-16 21:00:36.160616000 +0100
@@ -3,6 +3,13 @@
 # include <sys/time.h>
 # include <time.h>
 # include <unistd.h>
+# include <stdlib.h>
+#include <stdint.h>
+# include <stdio.h>	/* printf() */
+# include <limits.h>	/* CHAR_BIT */
+#if 0
+# include <inttypes.h>	/* format spec PRIX64: ll/l + X on 32/64-bit arch */
+#endif
 
 /* Work around redefinition to rpl_putenv by other config tests.  */
 #undef putenv
@@ -16,6 +23,78 @@
 };
 #define N_STRINGS (sizeof (tz_strings) / sizeof (tz_strings[0]))
 
+/* Count the bits set in any unsigned integer type.
+ * Returns the precision (width - padding bits - sign bit) iff given
+ * the xxx_MAX value of any integer type, signed or unsigned.
+ * From SEI CERT C Coding Standard:
+ * Rules for Developing Safe, Reliable, and Secure Systems (2016)
+ */
+size_t
+popcount (num)
+uintmax_t num;
+{
+  size_t cnt = 0;
+    
+  while (num != 0)
+    {
+      if (num % 2 == 1)
+      cnt++;
+      num >>= 1;
+    }
+  return cnt;
+}
+#define PRECISION(max_value) popcount(max_value)
+
+/* Guess the maximum value of a time_t from it's storage width.
+ * ASSERT time_t is not a floating point, or of any arcane width, or unsigned.
+ * Only 4...8 byte width of a time_t are tested.
+ * On error: returns (time_t)(-1)
+ */
+time_t
+guess_time_t_max ()
+{
+  time_t t0, t1 = (time_t)(-1);
+  size_t size, prec;
+
+  switch ((size = sizeof(time_t)))
+    {
+      case 4:
+	prec = PRECISION((time_t) 0xFFFFFFFF);
+	break;
+      case 5:
+	prec = PRECISION((time_t) 0xFFFFFFFFFF);
+	break;
+      case 6:
+	prec = PRECISION((time_t) 0xFFFFFFFFFFFF);
+	break;
+      case 7:
+	prec = PRECISION((time_t) 0xFFFFFFFFFFFFFF);
+	break;
+      case 8:
+	prec = PRECISION((time_t) 0xFFFFFFFFFFFFFFFF);
+	break;
+      default:
+	prec = 1;
+	break;
+    }
+  prec--; /* assumption: time_t is signed */
+  if (prec)
+    {
+      t0 = (time_t) 1 << (prec - 1);
+      t1 = t0|(t0 - 1);
+    }
+
+  /* FIXME not portable: time_t can be floating point type,
+   * or another integer type other than long or long long.
+   *
+  fprintf (stderr, "time_t_max\t= 0x%"PRIX64"\n", t1);*/
+  fprintf (stderr, "sizeof(time_t)\t= %2zd byte\n", size);
+  fprintf (stderr, "precision\t= %2zd bit\n", prec);
+  fprintf (stderr, "padding\t\t= %2zd bit\n", size*CHAR_BIT - prec - 1 /* sign */);
+
+  return t1;
+}
+
 /* Fail if mktime fails to convert a date in the spring-forward gap.
    Based on a problem report from Andreas Jaeger.  */
 static void
@@ -106,9 +185,7 @@
   time_t t, delta;
   int i, j;
 
-  for (time_t_max = 1; 0 < time_t_max; time_t_max *= 2)
-    continue;
-  time_t_max--;
+  time_t_max = guess_time_t_max ();
   delta = time_t_max / 997; /* a suitable prime number */
   for (i = 0; i < N_STRINGS; i++)
     {
@@ -128,3 +205,4 @@
   spring_forward_gap ();
   exit (0);
 }
+/*! vi: set ai tabstop=8 shiftwidth=2: */

--nextPart1974885.4WAli8B44Z--






Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1648904.MsCH1bHPGx>