[PATCH v2 14/14] stdio-common: Convert macros across scanf input specifier tests

Maciej W. Rozycki macro@orcam.me.uk
Thu Jun 5 17:59:36 GMT 2025


From: Maciej W. Rozycki <macro@redhat.com>

Convert 'compare_real', 'read_real', and 'verify_input' macros to 
functions so as to improve readability and avoid pitfalls.
---
Changes from v1 (formerly 15/15):

- Factor in the removal of former 09/15.
---
 stdio-common/tst-scanf-format-character.h                   |  133 +-
 stdio-common/tst-scanf-format-integer.h                     |   55 -
 stdio-common/tst-scanf-format-real.h                        |  597 ++++++------
 stdio-common/tst-scanf-format-skeleton.c                    |    5 
 sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c |   18 
 5 files changed, 410 insertions(+), 398 deletions(-)

glibc-tst-scanf-format-all-skeleton-function.diff
Index: glibc/stdio-common/tst-scanf-format-character.h
===================================================================
--- glibc.orig/stdio-common/tst-scanf-format-character.h
+++ glibc/stdio-common/tst-scanf-format-character.h
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <stdbool.h>
 #include <string.h>
 
 #include <support/next_to_fault.h>
@@ -62,69 +63,69 @@ do									\
   }									\
 while (0)
 
-#define verify_input(f, val, count, errp)				\
-({									\
-  __label__ out, skip;							\
-  bool match = true;							\
-  int err = 0;								\
-  size_t i;								\
-  int ch;								\
-									\
-  for (i = 0; i < count; i++)						\
-    {									\
-      ch = read_input ();						\
-      if (ch < 0)							\
-	{								\
-	  err = ch;							\
-	  goto out;							\
-	}								\
-      if (ch == ':' && val[i] == '\0' && f == 's')			\
-	goto skip;							\
-      if (ch != val[i])							\
-	{								\
-	  match = false;						\
-	  goto out;							\
-	}								\
-    }									\
-  ch = read_input ();							\
-  if (ch < 0)								\
-    {									\
-      err = ch;								\
-      goto out;								\
-    }									\
-									\
-skip:									\
-  if (f != 'c' && val[i++] != '\0')					\
-    {									\
-      err = OUTPUT_TERM;						\
-      goto out;								\
-    }									\
-  if (val[i] != '\xa5')							\
-    {									\
-      err = OUTPUT_OVERRUN;						\
-      goto out;								\
-    }									\
-									\
-  while (ch != ':')							\
-    {									\
-      ch = read_input ();						\
-      if (ch < 0)							\
-	{								\
-	  err = ch;							\
-	  goto out;							\
-	}								\
-      match = false;							\
-    }									\
-									\
-out:									\
-  if (err || !match)							\
-    {									\
-      printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__);	\
-      for (size_t j = 0; j <= i; j++)					\
-	printf ("%c", val[j]);						\
-      printf ("'\n");							\
-    }									\
-									\
-  *errp = err;								\
-  match;								\
-})
+static bool
+verify_input (char f, type_t val, long long count, int *errp)
+{
+  bool match = true;
+  int err = 0;
+  size_t i;
+  int ch;
+
+  for (i = 0; i < count; i++)
+    {
+      ch = read_input ();
+      if (ch < 0)
+	{
+	  err = ch;
+	  goto out;
+	}
+      if (ch == ':' && val[i] == '\0' && f == 's')
+	goto skip;
+      if (ch != val[i])
+	{
+	  match = false;
+	  goto out;
+	}
+    }
+  ch = read_input ();
+  if (ch < 0)
+    {
+      err = ch;
+      goto out;
+    }
+
+skip:
+  if (f != 'c' && val[i++] != '\0')
+    {
+      err = OUTPUT_TERM;
+      goto out;
+    }
+  if (val[i] != '\xa5')
+    {
+      err = OUTPUT_OVERRUN;
+      goto out;
+    }
+
+  while (ch != ':')
+    {
+      ch = read_input ();
+      if (ch < 0)
+	{
+	  err = ch;
+	  goto out;
+	}
+      match = false;
+    }
+
+out:
+  if (err || !match)
+    {
+      printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__);
+      for (size_t j = 0; j <= i; j++)
+	printf ("%c", val[j]);
+      printf ("'\n");
+    }
+
+  *errp = err;
+  return match;
+}
Index: glibc/stdio-common/tst-scanf-format-integer.h
===================================================================
--- glibc.orig/stdio-common/tst-scanf-format-integer.h
+++ glibc/stdio-common/tst-scanf-format-integer.h
@@ -16,36 +16,45 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <stdbool.h>
 #include <string.h>
 
 /* Reference data is a signed decimal integer constant to compare against
    arithmetically.  */
 
+/* Tweak our environment according to any TYPE_T_UNSIGNED_P setting
+   supplied by the individual test case.  */
+#ifdef TYPE_T_UNSIGNED_P
+# define UNSIGNED unsigned
+#else
+# define UNSIGNED
+#endif
+
 #define pointer_to_value(val) (&(val))
 
 #define initialize_value(val)						\
   memset (&val, 0xa5, sizeof (val))
 
-#define verify_input(f, val, count, errp)				\
-({									\
-  __label__ out;							\
-  bool match = true;							\
-  int err;								\
-									\
-  UNSIGNED long long v = read_integer (&err);				\
-  if (err < 0)								\
-    goto out;								\
-  match = val == v;							\
-									\
-out:									\
-  if (err || !match)							\
-    {									\
-      printf ("error: %s:%d: input: %016llx\n",				\
-	      __FILE__, __LINE__, (long long) val);			\
-      printf ("error: %s:%d: value: %016llx\n",				\
-	      __FILE__, __LINE__, v);					\
-    }									\
-									\
-  *errp = err;								\
-  match;								\
-})
+static bool
+verify_input (char f, type_t val, long long count, int *errp)
+{
+  bool match = true;
+  int err;
+
+  UNSIGNED long long v = read_integer (&err);
+  if (err < 0)
+    goto out;
+  match = val == v;
+
+out:
+  if (err || !match)
+    {
+      printf ("error: %s:%d: input: %016llx\n",
+	      __FILE__, __LINE__, (long long) val);
+      printf ("error: %s:%d: value: %016llx\n",
+	      __FILE__, __LINE__, v);
+    }
+
+  *errp = err;
+  return match;
+}
Index: glibc/stdio-common/tst-scanf-format-real.h
===================================================================
--- glibc.orig/stdio-common/tst-scanf-format-real.h
+++ glibc/stdio-common/tst-scanf-format-real.h
@@ -66,301 +66,306 @@
 #define initialize_value(val)						\
   memset (&val, 0xa5, sizeof (val))
 
-#define compare_real(x, y)						\
-  (memcmp (&(x), &(y), sizeof (y)) == 0)
+#ifndef compare_real
+static bool
+compare_real (type_t x, type_t y)
+{
+  return memcmp (&x, &y, sizeof (y)) == 0;
+}
+#endif
 
-#define verify_input(f, val, count, errp)				\
-({									\
-  __label__ out;							\
-  bool match = true;							\
-  int errx = 0;								\
-  type_t v;								\
-									\
-  initialize_value (v);							\
-  /* Make sure it's been committed.  */					\
-  __asm__ ("" : : : "memory");						\
-									\
-  v = read_real (&errx);						\
-  if (errx < 0)								\
-    goto out;								\
-									\
-  match = compare_real (val, v);					\
-  if (!match)								\
-    {									\
-      union								\
-	{								\
-	  type_t v;							\
-	  unsigned char x[sizeof (type_t)];				\
-	}								\
-      uv = { .v = v }, ui = { .v = val };				\
-									\
-      printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__);	\
-      for (size_t j = 0; j < sizeof (ui.x); j++)			\
-	printf ("%02hhx", ui.x[j]);					\
-      printf ("'\n");							\
-      printf ("error: %s:%d: value buffer: `", __FILE__, __LINE__);	\
-      for (size_t j = 0; j < sizeof (uv.x); j++)			\
-	printf ("%02hhx", uv.x[j]);					\
-      printf ("'\n");							\
-    }									\
-									\
-out:									\
-  *errp = errx;								\
-  match;								\
-})
+static type_t
+read_real (int *errp)
+{
+  bool m = false;
+  int err = 0;
+  type_t v;
+  int ch;
 
-#define read_real(errp)							\
-({									\
-  __label__ out;							\
-  bool m = false;							\
-  int err = 0;								\
-  type_t v;								\
-  int ch;								\
-									\
-  ch = read_input ();							\
-  if (ch == '-' || ch == '+')						\
-    {									\
-      m = ch == '-';							\
-      ch = read_input ();						\
-    }									\
-									\
-  switch (ch)								\
-    {									\
-    case '0':								\
-      break;								\
-    case 'I':								\
-    case 'i':								\
-      {									\
-	static const char unf[] = { 'N', 'F' };				\
-	static const char lnf[] = { 'n', 'f' };				\
-	size_t i;							\
-									\
-	for (i = 0; i < sizeof (unf); i++)				\
-	  {								\
-	    ch = read_input ();						\
-	    if (ch != unf[i] && ch != lnf[i])				\
-	      {								\
-		err = ch < 0 ? ch : INPUT_FORMAT;			\
-		v = NAN;						\
-		goto out;						\
-	      }								\
-	  }								\
-									\
-	ch = read_input ();						\
-	if (ch == ':')							\
-	  {								\
-	    v = m ? -INFINITY : +INFINITY;				\
-	    goto out;							\
-	  }								\
-									\
-	static const char uinity[] = { 'I', 'N', 'I', 'T', 'Y' };	\
-	static const char linity[] = { 'i', 'n', 'i', 't', 'y' };	\
-									\
-	for (i = 0; i < sizeof (uinity); i++)				\
-	  {								\
-	    if (ch != uinity[i] && ch != linity[i])			\
-	      {								\
-		err = ch < 0 ? ch : INPUT_FORMAT;			\
-		v = NAN;						\
-		goto out;						\
-	      }								\
-	    ch = read_input ();						\
-	  }								\
-	if (ch == ':')							\
-	  {								\
-	    v = m ? -INFINITY : +INFINITY;				\
-	    goto out;							\
-	  }								\
-      }									\
-      err = ch < 0 ? ch : INPUT_FORMAT;					\
-      v = NAN;								\
-      goto out;								\
-									\
-    case 'N':								\
-    case 'n':								\
-      {									\
-	static const char uan[] = { 'A', 'N' };				\
-	static const char lan[] = { 'a', 'n' };				\
-	size_t i;							\
-									\
-	for (i = 0; i < sizeof (uan); i++)				\
-	  {								\
-	    ch = read_input ();						\
-	    if (ch != uan[i] && ch != lan[i])				\
-	      {								\
-		err = ch < 0 ? ch : INPUT_FORMAT;			\
-		v = NAN;						\
-		goto out;						\
-	      }								\
-	  }								\
-									\
-	ch = read_input ();						\
-	if (ch == ':')							\
-	  {								\
-	    v = m ? -nan (v, ".") : nan (v, ".");			\
-	    goto out;							\
-	  }								\
-									\
-	if (ch == '(')							\
-	  {								\
-	    size_t seq_size = 0;					\
-	    char *seq = NULL;						\
-	    i = 0;							\
-	    while (1)							\
-	      {								\
-		if (i == seq_size)					\
-		  {							\
-		    seq_size += SIZE_CHUNK;				\
-		    seq = xrealloc (seq, seq_size);			\
-		  }							\
-		ch = read_input ();					\
-		if (ch == ')')						\
-		  break;						\
-		if (ch != '_' && !isdigit (ch)				\
-		    && !(ch >= 'A' && ch <= 'Z')			\
-		    && !(ch >= 'a' && ch <= 'z'))			\
-		  {							\
-		    free (seq);						\
-		    err = ch < 0 ? ch : INPUT_FORMAT;			\
-		    v = NAN;						\
-		    goto out;						\
-		  }							\
-		seq[i++] = ch;						\
-	      }								\
-	    seq[i] = '\0';						\
-									\
-	    ch = read_input ();						\
-	    if (ch == ':')						\
-	      {								\
-		v = m ? -nan (v, seq) : nan (v, seq);			\
-		free (seq);						\
-		goto out;						\
-	      }								\
-	    free (seq);							\
-	  }								\
-      }									\
-      err = ch < 0 ? ch : INPUT_FORMAT;					\
-      v = NAN;								\
-      goto out;								\
-									\
-    default:								\
-      err = ch < 0 ? ch : INPUT_FORMAT;					\
-      v = NAN;								\
-      goto out;								\
-    }									\
-									\
-  ch = read_input ();							\
-  if (ch != 'X' && ch != 'x')						\
-    {									\
-      err = ch < 0 ? ch : INPUT_FORMAT;					\
-      v = NAN;								\
-      goto out;								\
-    }									\
-									\
-  type_t f = m ? -1.0 : 1.0;						\
-  v = m ? -0.0 : 0.0;							\
-  int i = 0;								\
-  do									\
-    {									\
-      int d = 0;							\
-									\
-      ch = read_input ();						\
-									\
-      if (i == 1)							\
-	switch (ch)							\
-	  {								\
-	  case '.':							\
-	    i++;							\
-	    continue;							\
-									\
-	  case ':':							\
-	  case 'P':							\
-	  case 'p':							\
-	    break;							\
-									\
-	  default:							\
-	    err = ch < 0 ? ch : INPUT_FORMAT;				\
-	    v = NAN;							\
-	    goto out;							\
-	  }								\
-									\
-      switch (ch)							\
-	{								\
-	case '0':							\
-	case '1':							\
-	case '2':							\
-	case '3':							\
-	case '4':							\
-	case '5':							\
-	case '6':							\
-	case '7':							\
-	case '8':							\
-	case '9':							\
-	  d = ch - '0';							\
-	  break;							\
-									\
-	case 'A':							\
-	case 'B':							\
-	case 'C':							\
-	case 'D':							\
-	case 'E':							\
-	case 'F':							\
-	  d = ch - 'A' + 10;						\
-	  break;							\
-									\
-	case 'a':							\
-	case 'b':							\
-	case 'c':							\
-	case 'd':							\
-	case 'e':							\
-	case 'f':							\
-	  d = ch - 'a' + 10;						\
-	  break;							\
-									\
-	case ':':							\
-	case 'P':							\
-	case 'p':							\
-	  if (i == 0)							\
-	    {								\
-	      err = INPUT_FORMAT;					\
-	      v = NAN;							\
-	      goto out;							\
-	    }								\
-	  break;							\
-									\
-	default:							\
-	  err = ch < 0 ? ch : INPUT_FORMAT;				\
-	  v = NAN;							\
-	  goto out;							\
-	}								\
-									\
-      v += f * d;							\
-      f /= 16.0l;							\
-      i++;								\
-    }									\
-  while (ch != ':' && ch != 'P' && ch != 'p');				\
-									\
-  long long exp = 0;							\
-  if (ch == 'P' || ch == 'p')						\
-    {									\
-      exp = read_integer (&err);					\
-      if (err)								\
-	{								\
-	  v = NAN;							\
-	  goto out;							\
-	}								\
-    }									\
-									\
-  errno = 0;								\
-  v = ldexp (v, exp);							\
-  if ((v == HUGE_VALL || v == -HUGE_VALL) && errno != 0)		\
-    {									\
-      err = INPUT_OVERFLOW;						\
-      v = NAN;								\
-      goto out;								\
-    }									\
-									\
-out:									\
-  *errp = err;								\
-  v;									\
-})
+  ch = read_input ();
+  if (ch == '-' || ch == '+')
+    {
+      m = ch == '-';
+      ch = read_input ();
+    }
+
+  switch (ch)
+    {
+    case '0':
+      break;
+    case 'I':
+    case 'i':
+      {
+	static const char unf[] = { 'N', 'F' };
+	static const char lnf[] = { 'n', 'f' };
+	size_t i;
+
+	for (i = 0; i < sizeof (unf); i++)
+	  {
+	    ch = read_input ();
+	    if (ch != unf[i] && ch != lnf[i])
+	      {
+		err = ch < 0 ? ch : INPUT_FORMAT;
+		v = NAN;
+		goto out;
+	      }
+	  }
+
+	ch = read_input ();
+	if (ch == ':')
+	  {
+	    v = m ? -INFINITY : +INFINITY;
+	    goto out;
+	  }
+
+	static const char uinity[] = { 'I', 'N', 'I', 'T', 'Y' };
+	static const char linity[] = { 'i', 'n', 'i', 't', 'y' };
+
+	for (i = 0; i < sizeof (uinity); i++)
+	  {
+	    if (ch != uinity[i] && ch != linity[i])
+	      {
+		err = ch < 0 ? ch : INPUT_FORMAT;
+		v = NAN;
+		goto out;
+	      }
+	    ch = read_input ();
+	  }
+	if (ch == ':')
+	  {
+	    v = m ? -INFINITY : +INFINITY;
+	    goto out;
+	  }
+      }
+      err = ch < 0 ? ch : INPUT_FORMAT;
+      v = NAN;
+      goto out;
+
+    case 'N':
+    case 'n':
+      {
+	static const char uan[] = { 'A', 'N' };
+	static const char lan[] = { 'a', 'n' };
+	size_t i;
+
+	for (i = 0; i < sizeof (uan); i++)
+	  {
+	    ch = read_input ();
+	    if (ch != uan[i] && ch != lan[i])
+	      {
+		err = ch < 0 ? ch : INPUT_FORMAT;
+		v = NAN;
+		goto out;
+	      }
+	  }
+
+	ch = read_input ();
+	if (ch == ':')
+	  {
+	    v = m ? -nan (v, ".") : nan (v, ".");
+	    goto out;
+	  }
+
+	if (ch == '(')
+	  {
+	    size_t seq_size = 0;
+	    char *seq = NULL;
+	    i = 0;
+	    while (1)
+	      {
+		if (i == seq_size)
+		  {
+		    seq_size += SIZE_CHUNK;
+		    seq = xrealloc (seq, seq_size);
+		  }
+		ch = read_input ();
+		if (ch == ')')
+		  break;
+		if (ch != '_' && !isdigit (ch)
+		    && !(ch >= 'A' && ch <= 'Z')
+		    && !(ch >= 'a' && ch <= 'z'))
+		  {
+		    free (seq);
+		    err = ch < 0 ? ch : INPUT_FORMAT;
+		    v = NAN;
+		    goto out;
+		  }
+		seq[i++] = ch;
+	      }
+	    seq[i] = '\0';
+
+	    ch = read_input ();
+	    if (ch == ':')
+	      {
+		v = m ? -nan (v, seq) : nan (v, seq);
+		free (seq);
+		goto out;
+	      }
+	    free (seq);
+	  }
+      }
+      err = ch < 0 ? ch : INPUT_FORMAT;
+      v = NAN;
+      goto out;
+
+    default:
+      err = ch < 0 ? ch : INPUT_FORMAT;
+      v = NAN;
+      goto out;
+    }
+
+  ch = read_input ();
+  if (ch != 'X' && ch != 'x')
+    {
+      err = ch < 0 ? ch : INPUT_FORMAT;
+      v = NAN;
+      goto out;
+    }
+
+  type_t f = m ? -1.0 : 1.0;
+  v = m ? -0.0 : 0.0;
+  int i = 0;
+  do
+    {
+      int d = 0;
+
+      ch = read_input ();
+
+      if (i == 1)
+	switch (ch)
+	  {
+	  case '.':
+	    i++;
+	    continue;
+
+	  case ':':
+	  case 'P':
+	  case 'p':
+	    break;
+
+	  default:
+	    err = ch < 0 ? ch : INPUT_FORMAT;
+	    v = NAN;
+	    goto out;
+	  }
+
+      switch (ch)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  d = ch - '0';
+	  break;
+
+	case 'A':
+	case 'B':
+	case 'C':
+	case 'D':
+	case 'E':
+	case 'F':
+	  d = ch - 'A' + 10;
+	  break;
+
+	case 'a':
+	case 'b':
+	case 'c':
+	case 'd':
+	case 'e':
+	case 'f':
+	  d = ch - 'a' + 10;
+	  break;
+
+	case ':':
+	case 'P':
+	case 'p':
+	  if (i == 0)
+	    {
+	      err = INPUT_FORMAT;
+	      v = NAN;
+	      goto out;
+	    }
+	  break;
+
+	default:
+	  err = ch < 0 ? ch : INPUT_FORMAT;
+	  v = NAN;
+	  goto out;
+	}
+
+      v += f * d;
+      f /= 16.0l;
+      i++;
+    }
+  while (ch != ':' && ch != 'P' && ch != 'p');
+
+  long long exp = 0;
+  if (ch == 'P' || ch == 'p')
+    {
+      exp = read_integer (&err);
+      if (err)
+	{
+	  v = NAN;
+	  goto out;
+	}
+    }
+
+  errno = 0;
+  v = ldexp (v, exp);
+  if ((v == HUGE_VALL || v == -HUGE_VALL) && errno != 0)
+    {
+      err = INPUT_OVERFLOW;
+      v = NAN;
+      goto out;
+    }
+
+out:
+  *errp = err;
+  return v;
+}
+
+static bool
+verify_input (char f, type_t val, long long count, int *errp)
+{
+  bool match = true;
+  int err = 0;
+  type_t v;
+
+  initialize_value (v);
+  /* Make sure it's been committed.  */
+  __asm__ ("" : : : "memory");
+
+  v = read_real (&err);
+  if (err < 0)
+    goto out;
+
+  match = compare_real (val, v);
+  if (!match)
+    {
+      union
+	{
+	  type_t v;
+	  unsigned char x[sizeof (type_t)];
+	}
+      uv = { .v = v }, ui = { .v = val };
+
+      printf ("error: %s:%d: input buffer: `", __FILE__, __LINE__);
+      for (size_t j = 0; j < sizeof (ui.x); j++)
+	printf ("%02hhx", ui.x[j]);
+      printf ("'\n");
+      printf ("error: %s:%d: value buffer: `", __FILE__, __LINE__);
+      for (size_t j = 0; j < sizeof (uv.x); j++)
+	printf ("%02hhx", uv.x[j]);
+      printf ("'\n");
+    }
+
+out:
+  *errp = err;
+  return match;
+}
Index: glibc/stdio-common/tst-scanf-format-skeleton.c
===================================================================
--- glibc.orig/stdio-common/tst-scanf-format-skeleton.c
+++ glibc/stdio-common/tst-scanf-format-skeleton.c
@@ -60,11 +60,6 @@
 #ifndef TYPE_T_UNSIGNED_P
 # define TYPE_T_UNSIGNED_P 0
 #endif
-#if TYPE_T_UNSIGNED_P
-# define UNSIGNED unsigned
-#else
-# define UNSIGNED
-#endif
 
 /* Read and return a single character from standard input, returning
    end-of-file or error status indication where applicable.  */
Index: glibc/sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c
===================================================================
--- glibc.orig/sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c
+++ glibc/sysdeps/ieee754/ldbl-96/tst-scanf-format-skeleton-ldouble.c
@@ -17,19 +17,21 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <math_ldbl.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
 
 typedef long double type_t;
 
-#include "tst-scanf-format-real.h"
+static bool
+compare_real (type_t x, type_t y)
+{
+  ieee_long_double_shape_type ux = { .value = x }, uy = { .value = y };
 
-#undef compare_real
-#define compare_real(x, y)						\
-({									\
-  ieee_long_double_shape_type ux = { .value = x }, uy = { .value = y };	\
-  (ux.parts.lsw == uy.parts.lsw && ux.parts.msw == uy.parts.msw		\
-   && ux.parts.sign_exponent == uy.parts.sign_exponent);	 	\
-})
+  return (ux.parts.lsw == uy.parts.lsw && ux.parts.msw == uy.parts.msw
+	  && ux.parts.sign_exponent == uy.parts.sign_exponent);
+}
+#define compare_real compare_real
 
+#include "tst-scanf-format-real.h"
 #include "tst-scanf-format-skeleton.c"


More information about the Libc-alpha mailing list