changeset 15340:03a50862ef09

snprintf: guarantee %1$d, for libintl Newer mingw (but not yet mingw64) provides two flavors of snprintf: _snprintf defers straight to msvcrt, which has broken return value and does not understand %llu or %zu; and snprintf, which fixes these two bugs but does not understand %1$s. Libintl specifically favors _snprintf, with broken return value, even when compiled on mingw with a fixed snprintf, because the only behavior which it wants to fix is %1$s handling. But this means that the replacement libintl_snprintf has a broken return. If one uses the 'snprintf-posix' module, then the gnulib replacement kicks in, and does everything that libintl needs, so on mingw, <libintl.h> specifically avoids overriding snprintf if it detected that gnulib replaced snprintf. However, if one only uses the 'snprintf' module and also uses libintl, this means there are two problems: 1. The gnulib 'snprintf' module does not replace the mingw snprintf function, because it has proper return values, while the libintl.h header knows that %1$d is broken so snprintf must be replaced, with the end result that the application gets the libintl replacement snprintf with broken return values in spite of the gnulib module. 2. Conversely, if the application did '#define snprintf snprintf', that would be enough to make libintl avoid installing its own replacement because libintl would see the define as a sign that gnulib is happy with snprintf. However, if gnulib didn't enforce %1$s, users can end up with translated strings that break when passed to the native snprintf. Happily, the gnulib snprintf replacement already guarantees %1$s without needing any further preprocessor macros defined, and without dragging in the LGPLv3+ bulk of snprintf-posix, so the problem boils down to guaranteeing that gnulib will replace snprintf if it lacks %1$s support. Basically, gnulib must replace snprintf under all the same conditions as libintl, as well as any other conditions of its own, if the libintl trick of deferring to gnulib is to work correctly. * m4/snprintf.m4 (gl_FUNC_SNPRINTF): Require %1$d support. * m4/vsnprintf.m4 (gl_FUNC_VSNPRINTF): Likewise. * doc/posix-functions/snprintf.texi (snprintf): Update. * doc/posix-functions/vsnprintf.texi (vsnprintf): Likewise. * tests/test-snprintf.c (main): Enhance test. * tests/test-vsnprintf.c (main): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
author Eric Blake <eblake@redhat.com>
date Fri, 01 Jul 2011 08:20:06 -0600
parents 7c4560676bcd
children e20383a4e296
files ChangeLog doc/posix-functions/snprintf.texi doc/posix-functions/vsnprintf.texi m4/snprintf.m4 m4/vsnprintf.m4 tests/test-snprintf.c tests/test-vsnprintf.c
diffstat 7 files changed, 62 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Jul 05 10:32:30 2011 +0200
+++ b/ChangeLog	Fri Jul 01 08:20:06 2011 -0600
@@ -1,3 +1,13 @@
+2011-07-05  Eric Blake  <eblake@redhat.com>
+
+	snprintf: guarantee %1$d, for libintl
+	* m4/snprintf.m4 (gl_FUNC_SNPRINTF): Require %1$d support.
+	* m4/vsnprintf.m4 (gl_FUNC_VSNPRINTF): Likewise.
+	* doc/posix-functions/snprintf.texi (snprintf): Update.
+	* doc/posix-functions/vsnprintf.texi (vsnprintf): Likewise.
+	* tests/test-snprintf.c (main): Enhance test.
+	* tests/test-vsnprintf.c (main): Likewise.
+
 2011-07-05  Jim Meyering  <meyering@redhat.com>
 
 	maint: exempt stdio-read.c and stdio-write.c from the cppi check
--- a/doc/posix-functions/snprintf.texi	Tue Jul 05 10:32:30 2011 +0200
+++ b/doc/posix-functions/snprintf.texi	Fri Jul 01 08:20:06 2011 -0600
@@ -12,12 +12,17 @@
 This function is missing on some platforms:
 IRIX 5.3, OSF/1 4.0, Solaris 2.5.1.
 @item
-This function does not return a byte count as specified in C99 on some platforms:
+This function does not support format directives that access arguments in an
+arbitrary order, such as @code{"%2$s"}, on some platforms:
+NetBSD 3.0, mingw, BeOS.
+@item
+This function does not return a byte count as specified in C99 on some
+platforms:
 HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 9, mingw.
 @item
 This function overwrites memory even when a size argument of 1 is passed on some
 platforms:
-Linux libc5.
+Linux libc5, BeOS.
 @end itemize
 
 Portability problems fixed by Gnulib module @code{snprintf-posix}:
@@ -50,10 +55,6 @@
 on some platforms:
 Solaris 11 2010-11.
 @item
-This function does not support format directives that access arguments in an
-arbitrary order, such as @code{"%2$s"}, on some platforms:
-NetBSD 3.0, mingw, BeOS.
-@item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, Cygwin 1.5.24, mingw.
 @item
@@ -83,10 +84,6 @@
 This function does not fully support the @samp{n} directive on some platforms:
 HP-UX 11, mingw.
 @item
-This function overwrites memory when a size = 1 argument is passed on some
-platforms:
-BeOS.
-@item
 This function overwrites memory even when a zero size argument is passed on some
 platforms:
 OSF/1 5.1.
--- a/doc/posix-functions/vsnprintf.texi	Tue Jul 05 10:32:30 2011 +0200
+++ b/doc/posix-functions/vsnprintf.texi	Fri Jul 01 08:20:06 2011 -0600
@@ -12,11 +12,16 @@
 This function is missing on some platforms:
 IRIX 5.3, OSF/1 4.0, Solaris 2.5.1.
 @item
+This function does not support format directives that access arguments in an
+arbitrary order, such as @code{"%2$s"}, on some platforms:
+NetBSD 3.0, mingw, BeOS.
+@item
 This function overwrites memory even when a size argument of 1 is passed on some
 platforms:
-Linux libc5.
+Linux libc5, BeOS.
 @item
-This function does not return a byte count as specified in C99 on some platforms:
+This function does not return a byte count as specified in C99 on some
+platforms:
 HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 9, mingw.
 @end itemize
 
@@ -50,10 +55,6 @@
 on some platforms:
 Solaris 11 2010-11.
 @item
-This function does not support format directives that access arguments in an
-arbitrary order, such as @code{"%2$s"}, on some platforms:
-NetBSD 3.0, mingw, BeOS.
-@item
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, Cygwin 1.5.24, mingw.
 @item
@@ -83,10 +84,6 @@
 This function does not fully support the @samp{n} directive on some platforms:
 HP-UX 11, mingw.
 @item
-This function overwrites memory when a size = 1 argument is passed on some
-platforms:
-BeOS.
-@item
 This function overwrites memory even when a zero size argument is passed on some
 platforms:
 HP-UX 11, OSF/1 5.1.
--- a/m4/snprintf.m4	Tue Jul 05 10:32:30 2011 +0200
+++ b/m4/snprintf.m4	Fri Jul 01 08:20:06 2011 -0600
@@ -1,9 +1,13 @@
-# snprintf.m4 serial 5
+# snprintf.m4 serial 6
 dnl Copyright (C) 2002-2004, 2007-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
+dnl Libintl 0.17 will replace snprintf only if it does not support %1$s,
+dnl but defers to any gnulib snprintf replacements.  Therefore, gnulib
+dnl must guarantee that the decision for replacing snprintf is a superset
+dnl of the reasons checked by libintl.
 AC_DEFUN([gl_FUNC_SNPRINTF],
 [
   AC_REQUIRE([gl_STDIO_H_DEFAULTS])
@@ -16,7 +20,12 @@
         gl_SNPRINTF_RETVAL_C99
         case "$gl_cv_func_snprintf_retval_c99" in
           *yes)
-            gl_cv_func_snprintf_usable=yes
+            gl_PRINTF_POSITIONS
+            case "$gl_cv_func_printf_positions" in
+              *yes)
+                gl_cv_func_snprintf_usable=yes
+                ;;
+            esac
             ;;
         esac
         ;;
--- a/m4/vsnprintf.m4	Tue Jul 05 10:32:30 2011 +0200
+++ b/m4/vsnprintf.m4	Fri Jul 01 08:20:06 2011 -0600
@@ -1,9 +1,13 @@
-# vsnprintf.m4 serial 5
+# vsnprintf.m4 serial 6
 dnl Copyright (C) 2002-2004, 2007-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
+dnl Libintl 0.17 will replace vsnprintf only if it does not support %1$s,
+dnl but defers to any gnulib vsnprintf replacements.  Therefore, gnulib
+dnl must guarantee that the decision for replacing vsnprintf is a superset
+dnl of the reasons checked by libintl.
 AC_DEFUN([gl_FUNC_VSNPRINTF],
 [
   AC_REQUIRE([gl_STDIO_H_DEFAULTS])
@@ -16,7 +20,12 @@
         gl_SNPRINTF_RETVAL_C99
         case "$gl_cv_func_snprintf_retval_c99" in
           *yes)
-            gl_cv_func_vsnprintf_usable=yes
+            gl_PRINTF_POSITIONS
+            case "$gl_cv_func_printf_positions" in
+              *yes)
+                gl_cv_func_vsnprintf_usable=yes
+                ;;
+            esac
             ;;
         esac
         ;;
--- a/tests/test-snprintf.c	Tue Jul 05 10:32:30 2011 +0200
+++ b/tests/test-snprintf.c	Fri Jul 01 08:20:06 2011 -0600
@@ -60,5 +60,13 @@
         }
     }
 
+  /* Test the support of the POSIX/XSI format strings with positions.  */
+  {
+    char result[100];
+    int retval = snprintf (result, sizeof (result), "%2$d %1$d", 33, 55);
+    ASSERT (strcmp (result, "55 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
   return 0;
 }
--- a/tests/test-vsnprintf.c	Tue Jul 05 10:32:30 2011 +0200
+++ b/tests/test-vsnprintf.c	Fri Jul 01 08:20:06 2011 -0600
@@ -73,5 +73,13 @@
         }
     }
 
+  /* Test the support of the POSIX/XSI format strings with positions.  */
+  {
+    char result[100];
+    int retval = my_snprintf (result, sizeof (result), "%2$d %1$d", 33, 55);
+    ASSERT (strcmp (result, "55 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
   return 0;
 }