Bug 6530 [1] causes "git show v0.99.6~1" to fail with error "your
vsnprintf is broken". The workaround avoids that, but it corrupts
system error messages in non-C locales.

The bug has been fixed since 2.17. If git is built with glibc, it can
know running libc version with gnu_get_libc_version() and avoid the
workaround on fixed versions. As a side effect, the workaround is
dropped for all non-glibc systems.

Tested on Gentoo Linux, glibc 2.17, amd64.

[1] http://sourceware.org/bugzilla/show_bug.cgi?id=6530

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 We could even dlopen and look for gnu_get_libc_version at runtime and
 drop USE_GLIBC define. But there may be other problems with dl* on
 other platforms..

 Somebody should test for the other two "USE_GLIBC = YesPlease" I
 added. I don't have Debian/FreeBSD nor any non-Linux GNU systems.

 Makefile         |  5 +++++
 config.mak.uname |  3 +++
 gettext.c        | 34 ++++++++++++++++++++++++++++------
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index af847f8..8df6d6d 100644
--- a/Makefile
+++ b/Makefile
@@ -66,6 +66,8 @@ all::
 # Define LIBC_CONTAINS_LIBINTL if your gettext implementation doesn't
 # need -lintl when linking.
 #
+# Define USE_GLIBC if your libc version is glibc >= 2.1.
+#
 # Define NO_MSGFMT_EXTENDED_OPTIONS if your implementation of msgfmt
 # doesn't support GNU extensions like --check and --statistics
 #
@@ -1203,6 +1205,9 @@ ifndef NO_GETTEXT
 ifndef LIBC_CONTAINS_LIBINTL
        EXTLIBS += -lintl
 endif
+ifdef USE_GLIBC
+       BASIC_CFLAGS += -DUSE_GLIBC
+endif
 endif
 ifdef NEEDS_SOCKET
        EXTLIBS += -lsocket
diff --git a/config.mak.uname b/config.mak.uname
index 82d549e..ffb01e0 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -33,6 +33,7 @@ ifeq ($(uname_S),Linux)
        HAVE_PATHS_H = YesPlease
        LIBC_CONTAINS_LIBINTL = YesPlease
        HAVE_DEV_TTY = YesPlease
+       USE_GLIBC = YesPlease
 endif
 ifeq ($(uname_S),GNU/kFreeBSD)
        NO_STRLCPY = YesPlease
@@ -40,6 +41,7 @@ ifeq ($(uname_S),GNU/kFreeBSD)
        HAVE_PATHS_H = YesPlease
        DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
        LIBC_CONTAINS_LIBINTL = YesPlease
+       USE_GLIBC = YesPlease
 endif
 ifeq ($(uname_S),UnixWare)
        CC = cc
@@ -236,6 +238,7 @@ ifeq ($(uname_S),GNU)
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
        LIBC_CONTAINS_LIBINTL = YesPlease
+       USE_GLIBC = YesPlease
 endif
 ifeq ($(uname_S),IRIX)
        NO_SETENV = YesPlease
diff --git a/gettext.c b/gettext.c
index 71e9545..91e679d 100644
--- a/gettext.c
+++ b/gettext.c
@@ -18,6 +18,13 @@
 #      endif
 #endif
 
+#ifdef USE_GLIBC
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <gnu/libc-version.h>
+#endif
+
 #ifdef GETTEXT_POISON
 int use_gettext_poison(void)
 {
@@ -30,6 +37,7 @@ int use_gettext_poison(void)
 
 #ifndef NO_GETTEXT
 static const char *charset;
+static int vsnprintf_workaround;
 static void init_gettext_charset(const char *domain)
 {
        /*
@@ -99,9 +107,7 @@ static void init_gettext_charset(const char *domain)
           $ LANGUAGE= LANG=de_DE.utf8 ./test
           test: Kein passendes Ger?t gefunden
 
-          In the long term we should probably see about getting that
-          vsnprintf bug in glibc fixed, and audit our code so it won't
-          fall apart under a non-C locale.
+          The vsnprintf bug has been fixed since 2.17.
 
           Then we could simply set LC_CTYPE from the environment, which would
           make things like the external perror(3) messages work.
@@ -112,20 +118,36 @@ static void init_gettext_charset(const char *domain)
           1. http://sourceware.org/bugzilla/show_bug.cgi?id=6530
           2. E.g. "Content-Type: text/plain; charset=UTF-8\n" in po/is.po
        */
-       setlocale(LC_CTYPE, "");
+       if (vsnprintf_workaround)
+               setlocale(LC_CTYPE, "");
        charset = locale_charset();
        bind_textdomain_codeset(domain, charset);
-       setlocale(LC_CTYPE, "C");
+       if (vsnprintf_workaround)
+               setlocale(LC_CTYPE, "C");
 }
 
 void git_setup_gettext(void)
 {
        const char *podir = getenv("GIT_TEXTDOMAINDIR");
 
+#ifdef USE_GLIBC
+       int major, minor;
+       const char *version = gnu_get_libc_version();
+
+       if (version && sscanf(version, "%d.%d", &major, &minor) == 2 &&
+           (major > 2 || (major == 2 && minor >= 17)))
+               vsnprintf_workaround = 0;
+       else
+               vsnprintf_workaround = 1;
+#endif
+
        if (!podir)
                podir = GIT_LOCALE_PATH;
        bindtextdomain("git", podir);
-       setlocale(LC_MESSAGES, "");
+       if (vsnprintf_workaround)
+               setlocale(LC_MESSAGES, "");
+       else
+               setlocale(LC_ALL, "");
        init_gettext_charset("git");
        textdomain("git");
 }
-- 
1.8.2.83.gc99314b

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to