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 <pclouds@xxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html