From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30882 invoked by alias); 11 Jul 2007 09:09:04 -0000 Received: (qmail 30862 invoked by uid 22791); 11 Jul 2007 09:09:02 -0000 X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 11 Jul 2007 09:08:49 +0000 Received: from sunsite.mff.cuni.cz (localhost.localdomain [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.8/8.13.8) with ESMTP id l6B9BhpM025417; Wed, 11 Jul 2007 11:11:43 +0200 Received: (from jakub@localhost) by sunsite.mff.cuni.cz (8.13.8/8.13.8/Submit) id l6B9BhE2025414; Wed, 11 Jul 2007 11:11:43 +0200 Date: Wed, 11 Jul 2007 09:09:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers Subject: [PATCH] Fix ENOMEM segfaults in intl code Message-ID: <20070711091142.GK4603@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2007-07/txt/msg00010.txt.bz2 Hi! The attached patch fixes a segfault when _nl_normalize_codeset returned NULL because of a malloc failure. Although _nl_explode_name returns a bitmask, it only uses a few low bits, so using -1 to signal a failure seems best to me. Silently pretending that the codeset is normalized seems to be a bad choice, so I think we should signal a failure. Here is a testcase. In addition to the occassional segfaults which are fixed by this patch the output is sometimes incorrectly encoded in EUC-JP (the original encoding of ja.po) - this happens when e.g. dlopen of the EUC-JP.so gconv module fails and in the end __gconv_open returns __GCONV_NOCONV. That's a separate bug I don't have a fix for. #define _GNU_SOURCE #include #include #include #include #include #include #include int mayret; void * malloc (size_t x) { void *(*fn) (size_t) = dlsym (RTLD_NEXT, "malloc"); if (mayret && (random () & 31) == 0) { errno = ENOMEM; return NULL; } return fn (x); } void free (void *x) { void (*fn) (void *) = dlsym (RTLD_NEXT, "free"); return fn (x); } void * realloc (void *p, size_t x) { void *(*fn) (void *, size_t) = dlsym (RTLD_NEXT, "realloc"); if (mayret && (random () & 7) == 0) { errno = ENOMEM; return NULL; } return fn (p, x); } void * calloc (size_t x, size_t y) { void *ret = malloc (x * y); if (ret != NULL) memset (ret, 0, x * y); return ret; } int main (int argc, char *argv[]) { char *msg; int i; long long l; if (argc > 1) l = strtoul (argv[1], NULL, 0); else { #ifdef __x86_64__ # define HP_TIMING_NOW(Var) \ ({ unsigned int _hi, _lo; \ asm volatile ("rdtsc" : "=a" (_lo), "=d" (_hi)); \ (Var) = ((unsigned long long int) _hi << 32) | _lo; }) #elif defined __i386__ # define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var)) #else # define HP_TIMING_NOW(Var) (Var) = 0 #endif HP_TIMING_NOW (l); } printf ("0x%x\n", (unsigned int) l); srandom ((unsigned int) l); setlocale (LC_ALL, "ja_JP.UTF-8"); mayret = 1; for (i = 0; i < 64; i++) { msg = strerror (i); puts (msg); } return 0; } 2007-07-11 Jakub Jelinek * intl/finddomain.c (_nl_find_domain): If _nl_explode_name returned -1, return NULL. * intl/explodename.c (_nl_explode_name): Return -1 if _nl_normalize_codeset failed. --- libc/intl/finddomain.c.jj 2006-04-07 05:27:32.000000000 +0200 +++ libc/intl/finddomain.c 2007-07-10 20:53:26.000000000 +0200 @@ -1,5 +1,5 @@ /* Handle list of needed message catalogs - Copyright (C) 1995-1999, 2000, 2001, 2002, 2004, 2006 + Copyright (C) 1995-1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Ulrich Drepper , 1995. @@ -126,6 +126,9 @@ _nl_find_domain (dirname, locale, domain we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */ mask = _nl_explode_name (locale, &language, &modifier, &territory, &codeset, &normalized_codeset); + if (mask == -1) + /* This means we are out of core. */ + return NULL; /* We need to protect modifying the _NL_LOADED_DOMAINS data. */ __libc_rwlock_wrlock (lock); --- libc/intl/explodename.c.jj 2006-04-07 08:59:29.000000000 +0200 +++ libc/intl/explodename.c 2007-07-10 20:46:47.000000000 +0200 @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-2002, 2003, 2006 Free Software Foundation, Inc. +/* Copyright (C) 1995-2002, 2003, 2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1995. @@ -108,7 +108,9 @@ _nl_explode_name (name, language, modifi { *normalized_codeset = _nl_normalize_codeset (*codeset, cp - *codeset); - if (strcmp (*codeset, *normalized_codeset) == 0) + if (*normalized_codeset == NULL) + return -1; + else if (strcmp (*codeset, *normalized_codeset) == 0) free ((char *) *normalized_codeset); else mask |= XPG_NORM_CODESET; Jakub