bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH] snprintf: guarantee %1$d, for libintl


From: Eric Blake
Subject: [PATCH] snprintf: guarantee %1$d, for libintl
Date: Fri, 1 Jul 2011 10:27:37 -0600

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, because 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 <address@hidden>
---

I tested the following scenarios:

changes to tests only (no m4 changes):
Linux and Cygwin passed the new tests with no modification (no
  replacement function needed)
cross-compiling from cygwin to mingw and mingw64 passed (since
  cross-compilation is pessimistic and replaced snprintf)
native compilation on mingw64 passed (since mingw64 does not
  have a working snprintf return value)
native compilation on mingw failed (since the mingw snprintf
  does not honor %1$s)

complete patch:
Linux and Cygwin continue to pass
cross-compilation to mingw and mingw64 still passes
native compilation on mingw64 still passes
native compilation on mingw now passes (the changed m4 macro
  was enough to force the gnulib replacement)

 ChangeLog                          |   10 ++++++++++
 doc/posix-functions/snprintf.texi  |   17 +++++++----------
 doc/posix-functions/vsnprintf.texi |   17 +++++++----------
 m4/snprintf.m4                     |    9 +++++++--
 m4/vsnprintf.m4                    |    9 +++++++--
 tests/test-snprintf.c              |    8 ++++++++
 tests/test-vsnprintf.c             |    8 ++++++++
 7 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index fcc2e6e..5f3ffb7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2011-07-01  Eric Blake  <address@hidden>
+
+       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-06-30  Paul Eggert  <address@hidden>

        xnanosleep: Rewrite to use new dtotimespec module.
diff --git a/doc/posix-functions/snprintf.texi 
b/doc/posix-functions/snprintf.texi
index d295cea..4e7a294 100644
--- a/doc/posix-functions/snprintf.texi
+++ b/doc/posix-functions/snprintf.texi
@@ -12,12 +12,17 @@ snprintf
 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.
address@hidden
+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 @@ snprintf
 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.
address@hidden
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, Cygwin 1.5.24, mingw.
 @item
@@ -83,10 +84,6 @@ snprintf
 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.
address@hidden
 This function overwrites memory even when a zero size argument is passed on 
some
 platforms:
 OSF/1 5.1.
diff --git a/doc/posix-functions/vsnprintf.texi 
b/doc/posix-functions/vsnprintf.texi
index e391f35..ca6e092 100644
--- a/doc/posix-functions/vsnprintf.texi
+++ b/doc/posix-functions/vsnprintf.texi
@@ -12,11 +12,16 @@ vsnprintf
 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.
address@hidden
 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 @@ vsnprintf
 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.
address@hidden
 This function doesn't support the @code{'} flag on some platforms:
 NetBSD 3.0, Cygwin 1.5.24, mingw.
 @item
@@ -83,10 +84,6 @@ vsnprintf
 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.
address@hidden
 This function overwrites memory even when a zero size argument is passed on 
some
 platforms:
 HP-UX 11, OSF/1 5.1.
diff --git a/m4/snprintf.m4 b/m4/snprintf.m4
index 8aa5dbe..11c7752 100644
--- a/m4/snprintf.m4
+++ b/m4/snprintf.m4
@@ -1,4 +1,4 @@
-# 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,
@@ -16,7 +16,12 @@ AC_DEFUN([gl_FUNC_SNPRINTF],
         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
         ;;
diff --git a/m4/vsnprintf.m4 b/m4/vsnprintf.m4
index e4725e4..809c72d 100644
--- a/m4/vsnprintf.m4
+++ b/m4/vsnprintf.m4
@@ -1,4 +1,4 @@
-# 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,
@@ -16,7 +16,12 @@ AC_DEFUN([gl_FUNC_VSNPRINTF],
         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
         ;;
diff --git a/tests/test-snprintf.c b/tests/test-snprintf.c
index 95a352d..18efed5 100644
--- a/tests/test-snprintf.c
+++ b/tests/test-snprintf.c
@@ -60,5 +60,13 @@ main (int argc, char *argv[])
         }
     }

+  /* 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;
 }
diff --git a/tests/test-vsnprintf.c b/tests/test-vsnprintf.c
index 5060836..6711f39 100644
--- a/tests/test-vsnprintf.c
+++ b/tests/test-vsnprintf.c
@@ -73,5 +73,13 @@ main (int argc, char *argv[])
         }
     }

+  /* 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;
 }
-- 
1.7.4.4




reply via email to

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