snprintf: guarantee %1$d, for libintl
authorEric Blake <eblake@redhat.com>
Fri, 1 Jul 2011 14:20:06 +0000 (08:20 -0600)
committerEric Blake <eblake@redhat.com>
Tue, 5 Jul 2011 16:13:40 +0000 (10:13 -0600)
commitc3153d2c0cf5f675ae13ae2bd1dee0f463b9c86a
tree4c7eac650c5c151006f8f7198b63186ef0513ff5
parent29757e0e9014e2b1ed26fac4228e849c3728bc32
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>
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