git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] gettext.c: only work around the vsnprintf bug on glibc < 2.17

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Nov 30, 2013, 01:51 UTC
Message-ID
<1385776291-21006-1-git-send-email-pclouds@gmail.com>

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@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
Next: Andreas Schwab
Message 1 of 12 in “gettext.c: only work around the vsnprintf bug on glibc < 2.17”
  1. gettext.c: only work around the vsnprintf bug on glibc < 2.17Nguyễn Thái Ngọc Duy, Nov 30, 2013
  2. Andreas SchwabNov 30, 2013
  3. gettext.c: only work around the vsnprintf bug on glibc < 2.17Nguyễn Thái Ngọc Duy, Nov 30, 2013
  4. Torsten BögershausenNov 30, 2013
  5. Torsten BögershausenNov 30, 2013
  6. Duy NguyenDec 1, 2013
  7. gettext.c: detect the vsnprintf bug at runtimeNguyễn Thái Ngọc Duy, Dec 1, 2013
  8. Trần Ngọc QuânDec 2, 2013
  9. Duy NguyenDec 2, 2013
  10. Trần Ngọc QuânDec 2, 2013
  11. Trần Ngọc QuânDec 2, 2013
  12. Duy NguyenDec 2, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.