This is the mail archive of the libc-hacker@sourceware.org mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix ENOMEM segfaults in intl code


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 <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <dlfcn.h>
#include <time.h>

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  <jakub@redhat.com>

	* 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 <drepper@gnu.org>, 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 <drepper@gnu.ai.mit.edu>, 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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]