bug-gnulib
[Top][All Lists]
Advanced

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

rethinking #if and 64-bit numbers (inttypes.h on Sun platforms)


From: Paul Eggert
Subject: rethinking #if and 64-bit numbers (inttypes.h on Sun platforms)
Date: Mon, 12 Nov 2007 15:59:28 -0800

Coreutils 'nl' dumps core on 32-bit Solaris sparc due to a mismatch
between types and formats.  The Solaris compiler has a buggy
preprocessor which misevaluates "#if -9223372036854775807LL < 0", I
suspect because it treats the constant as being unsigned.  This causes
'configure' to decide that 'long long int' isn't supported.  And yet
the print formats like PRIdMAX continue to use %lld.  The mismatch
causes printf to dump core.

I considered working around the problem by causing 32-bit Solaris
builds to fall back into a 32-bit-only world.  But that is too
drastic; it would break large-file support, for example.

Instead, on second thought, I think my patch of the last month in this
area was too drastic.  Instead of insisting on full support for 'long
long' in the preprocessor, we can get by with the old test (thus
allowing the Sun preprocessor to pass), so long as we avoid doing
64-bit tests inside #ifs.  This isn't great either, but it's the
lesser of two evils.

I installed this patch accordingly.

2007-11-12  Paul Eggert  <address@hidden>

        Don't insist on 'long long int' support in the preprocessor.  It
        breaks too many things.  For example, PRIdMAX still uses a 'long
        long int' format with the latest Sun compiler, even though
        HAVE_LONG_LONG_INT isn't defined due to that compiler's
        preprocessor problem.  This causes the latest coreutils to dump
        core on Solaris 10 sparc with the Sun C compiler.
        Instead, fix the 2007-10-16 problem in a different way, by evaluating
        the troublesome expressions at configure-time, not at #if-time.
        * m4/longlong.m4 (_AC_TYPE_LONG_LONG_SNIPPET): Don't test the
        preprocessor.
        * m4/inttypes.m4 (gl_INTTYPES_H): Move the #if checks into
        compile-time C checks, done at 'configure'-time.
        (gl_INTTYPES_CHECK_LONG_LONG_INT_CONDITION): New macro.
        * modules/inttypes (Makefile): Substitute the new symbols that
        gl_INTTYPES_H now generates.
        * lib/inttypes.in.h: Don't use constants wider than 'long' in #if.

diff --git a/lib/inttypes.in.h b/lib/inttypes.in.h
index f9f3119..8a24850 100644
--- a/lib/inttypes.in.h
+++ b/lib/inttypes.in.h
@@ -165,7 +165,7 @@
 #  endif
 # endif
 # ifdef INT64_MAX
-#  if INT64_MAX == LONG_MAX
+#  if @INT64_MAX_EQ_LONG_MAX@
 #   define _PRI64_PREFIX "l"
 #  elif defined _MSC_VER || defined __MINGW32__
 #   define _PRI64_PREFIX "I64"
@@ -182,7 +182,7 @@
 #  endif
 # endif
 # ifdef UINT64_MAX
-#  if UINT64_MAX == ULONG_MAX
+#  if @UINT64_MAX_EQ_ULONG_MAX@
 #   define _PRIu64_PREFIX "l"
 #  elif defined _MSC_VER || defined __MINGW32__
 #   define _PRIu64_PREFIX "I64"
@@ -483,7 +483,7 @@

 # if !defined PRIdMAX || @PRI_MACROS_BROKEN@
 #  undef PRIdMAX
-#  if INTMAX_MAX > INT32_MAX
+#  if @INT32_MAX_LT_INTMAX_MAX@
 #   define PRIdMAX PRId64
 #  else
 #   define PRIdMAX "ld"
@@ -491,7 +491,7 @@
 # endif
 # if !defined PRIiMAX || @PRI_MACROS_BROKEN@
 #  undef PRIiMAX
-#  if INTMAX_MAX > INT32_MAX
+#  if @INT32_MAX_LT_INTMAX_MAX@
 #   define PRIiMAX PRIi64
 #  else
 #   define PRIiMAX "li"
@@ -499,7 +499,7 @@
 # endif
 # if !defined PRIoMAX || @PRI_MACROS_BROKEN@
 #  undef PRIoMAX
-#  if UINTMAX_MAX > UINT32_MAX
+#  if @UINT32_MAX_LT_UINTMAX_MAX@
 #   define PRIoMAX PRIo64
 #  else
 #   define PRIoMAX "lo"
@@ -507,7 +507,7 @@
 # endif
 # if !defined PRIuMAX || @PRI_MACROS_BROKEN@
 #  undef PRIuMAX
-#  if UINTMAX_MAX > UINT32_MAX
+#  if @UINT32_MAX_LT_UINTMAX_MAX@
 #   define PRIuMAX PRIu64
 #  else
 #   define PRIuMAX "lu"
@@ -515,7 +515,7 @@
 # endif
 # if !defined PRIxMAX || @PRI_MACROS_BROKEN@
 #  undef PRIxMAX
-#  if UINTMAX_MAX > UINT32_MAX
+#  if @UINT32_MAX_LT_UINTMAX_MAX@
 #   define PRIxMAX PRIx64
 #  else
 #   define PRIxMAX "lx"
@@ -523,7 +523,7 @@
 # endif
 # if !defined PRIXMAX || @PRI_MACROS_BROKEN@
 #  undef PRIXMAX
-#  if UINTMAX_MAX > UINT32_MAX
+#  if @UINT32_MAX_LT_UINTMAX_MAX@
 #   define PRIXMAX PRIX64
 #  else
 #   define PRIXMAX "lX"
@@ -658,7 +658,7 @@
 #  endif
 # endif
 # ifdef INT64_MAX
-#  if INT64_MAX == LONG_MAX
+#  if @INT64_MAX_EQ_LONG_MAX@
 #   define _SCN64_PREFIX "l"
 #  elif defined _MSC_VER || defined __MINGW32__
 #   define _SCN64_PREFIX "I64"
@@ -675,7 +675,7 @@
 #  endif
 # endif
 # ifdef UINT64_MAX
-#  if UINT64_MAX == ULONG_MAX
+#  if @UINT64_MAX_EQ_ULONG_MAX@
 #   define _SCNu64_PREFIX "l"
 #  elif defined _MSC_VER || defined __MINGW32__
 #   define _SCNu64_PREFIX "I64"
@@ -958,7 +958,7 @@

 # if !defined SCNdMAX || @PRI_MACROS_BROKEN@
 #  undef SCNdMAX
-#  if INTMAX_MAX > INT32_MAX
+#  if @INT32_MAX_LT_INTMAX_MAX@
 #   define SCNdMAX SCNd64
 #  else
 #   define SCNdMAX "ld"
@@ -966,7 +966,7 @@
 # endif
 # if !defined SCNiMAX || @PRI_MACROS_BROKEN@
 #  undef SCNiMAX
-#  if INTMAX_MAX > INT32_MAX
+#  if @INT32_MAX_LT_INTMAX_MAX@
 #   define SCNiMAX SCNi64
 #  else
 #   define SCNiMAX "li"
@@ -974,7 +974,7 @@
 # endif
 # if !defined SCNoMAX || @PRI_MACROS_BROKEN@
 #  undef SCNoMAX
-#  if UINTMAX_MAX > UINT32_MAX
+#  if @UINT32_MAX_LT_UINTMAX_MAX@
 #   define SCNoMAX SCNo64
 #  else
 #   define SCNoMAX "lo"
@@ -982,7 +982,7 @@
 # endif
 # if !defined SCNuMAX || @PRI_MACROS_BROKEN@
 #  undef SCNuMAX
-#  if UINTMAX_MAX > UINT32_MAX
+#  if @UINT32_MAX_LT_UINTMAX_MAX@
 #   define SCNuMAX SCNu64
 #  else
 #   define SCNuMAX "lu"
@@ -990,7 +990,7 @@
 # endif
 # if !defined SCNxMAX || @PRI_MACROS_BROKEN@
 #  undef SCNxMAX
-#  if UINTMAX_MAX > UINT32_MAX
+#  if @UINT32_MAX_LT_UINTMAX_MAX@
 #   define SCNxMAX SCNx64
 #  else
 #   define SCNxMAX "lx"
diff --git a/m4/inttypes.m4 b/m4/inttypes.m4
index 8f949d0..b17cbda 100644
--- a/m4/inttypes.m4
+++ b/m4/inttypes.m4
@@ -207,11 +207,73 @@ const char *l = /* implicit string concatenation */
       HAVE_DECL_STRTOUMAX=0
     fi

+    gl_INTTYPES_CHECK_LONG_LONG_INT_CONDITION(
+      [INT32_MAX_LT_INTMAX_MAX],
+      [defined INT32_MAX && defined INTMAX_MAX],
+      [INT32_MAX < INTMAX_MAX],
+      [sizeof (int) < sizeof (long long int)])
+    gl_INTTYPES_CHECK_LONG_LONG_INT_CONDITION(
+      [INT64_MAX_EQ_LONG_MAX],
+      [defined INT64_MAX],
+      [INT64_MAX == LONG_MAX],
+      [sizeof (long long int) == sizeof (long int)])
+    gl_INTTYPES_CHECK_LONG_LONG_INT_CONDITION(
+      [UINT32_MAX_LT_UINTMAX_MAX],
+      [defined UINT32_MAX && defined UINTMAX_MAX],
+      [UINT32_MAX < UINTMAX_MAX],
+      [sizeof (unsigned int) < sizeof (unsigned long long int)])
+    gl_INTTYPES_CHECK_LONG_LONG_INT_CONDITION(
+      [UINT64_MAX_EQ_ULONG_MAX],
+      [defined UINT64_MAX],
+      [UINT64_MAX == ULONG_MAX],
+      [sizeof (unsigned long long int) == sizeof (unsigned long int)])
+
     INTTYPES_H='inttypes.h'
   fi
   AC_SUBST(INTTYPES_H)
 ])

+# Define the symbol $1 to be 1 if the condition is true, 0 otherwise.
+# If $2 is true, the condition is $3; otherwise if long long int is supported
+# approximate the condition with $4; otherwise, assume the condition is false.
+# The condition should work on all C99 platforms; the approximations should be
+# good enough to work on all practical pre-C99 platforms.
+# $2 is evaluated by the C preprocessor, $3 and $4 as compile-time constants.
+AC_DEFUN([gl_INTTYPES_CHECK_LONG_LONG_INT_CONDITION],
+[
+  AC_CACHE_CHECK([whether $3],
+    [gl_cv_test_$1],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+         [[/* Work also in C++ mode.  */
+           #define __STDC_LIMIT_MACROS 1
+
+           /* Work if build is not clean.  */
+           #define _GL_JUST_INCLUDE_SYSTEM_STDINT_H
+
+           #include <limits.h>
+           #if HAVE_STDINT_H
+            #include <stdint.h>
+           #endif
+
+           #if $2
+            #define CONDITION ($3)
+           #elif HAVE_LONG_LONG_INT
+            #define CONDITION ($4)
+           #else
+            #define CONDITION 0
+           #endif
+           int test[CONDITION ? 1 : -1];]])],
+       [gl_cv_test_$1=yes],
+       [gl_cv_test_$1=no])])
+  if test $gl_cv_test_$1 = yes; then
+    $1=1;
+  else
+    $1=0;
+  fi
+  AC_SUBST([$1])
+])
+
 AC_DEFUN([gl_INTTYPES_MODULE_INDICATOR],
 [
   dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
diff --git a/m4/longlong.m4 b/m4/longlong.m4
index a72e53b..15bf9da 100644
--- a/m4/longlong.m4
+++ b/m4/longlong.m4
@@ -82,13 +82,10 @@ AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT],
 AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET],
 [
   AC_LANG_PROGRAM(
-    [[/* Test preprocessor.  */
-      #if ! (-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
-        error in preprocessor;
-      #endif
-      #if ! (18446744073709551615ULL <= -1ull)
-        error in preprocessor;
-      #endif
+    [[/* For now, do not test the preprocessor; as of 2007 there are too many
+        implementations with broken preprocessors.  Perhaps this can
+        be revisited in 2012.  In the meantime, code should not expect
+        #if to work with literals wider than 32 bits.  */
       /* Test literals.  */
       long long int ll = 9223372036854775807ll;
       long long int nll = -9223372036854775807LL;
diff --git a/modules/inttypes b/modules/inttypes
index 2199e4b..91907d9 100644
--- a/modules/inttypes
+++ b/modules/inttypes
@@ -37,6 +37,10 @@ inttypes.h: inttypes.in.h
              -e 's/@''HAVE_DECL_IMAXDIV''@/$(HAVE_DECL_IMAXDIV)/g' \
              -e 's/@''HAVE_DECL_STRTOIMAX''@/$(HAVE_DECL_STRTOIMAX)/g' \
              -e 's/@''HAVE_DECL_STRTOUMAX''@/$(HAVE_DECL_STRTOUMAX)/g' \
+             -e 's/@''INT32_MAX_LT_INTMAX_MAX''@/$(INT32_MAX_LT_INTMAX_MAX)/g' 
\
+             -e 's/@''INT64_MAX_EQ_LONG_MAX''@/$(INT64_MAX_EQ_LONG_MAX)/g' \
+             -e 
's/@''UINT32_MAX_LT_UINTMAX_MAX''@/$(UINT32_MAX_LT_UINTMAX_MAX)/g' \
+             -e 's/@''UINT64_MAX_EQ_ULONG_MAX''@/$(UINT64_MAX_EQ_ULONG_MAX)/g' 
\
              -e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
              < $(srcdir)/inttypes.in.h; \
        } > address@hidden




reply via email to

[Prev in Thread] Current Thread [Next in Thread]