This is the mail archive of the newlib-cvs@sourceware.org mailing list for the newlib project.


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

[newlib-cygwin] Fix multiple thinkos in newlocale


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=d7281b92abb47d3f10c1ead20b16877c39a7afdd

commit d7281b92abb47d3f10c1ead20b16877c39a7afdd
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Tue Jul 26 23:36:04 2016 +0200

    Fix multiple thinkos in newlocale
    
    - Setting the categories strings in tmp_locale short-circuits
      __loadlocale.  Use a new_categories array instead, just as in
      _setlocale_r.
    
    - If we have a base, copy over the *not* defined categories in
      category_mask in the first place.  Rearrange loop accordingly.
    
    - Free base right in newlocale.
    
    Signed-off by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 newlib/libc/locale/newlocale.c | 113 +++++++++++++++++++++--------------------
 1 file changed, 59 insertions(+), 54 deletions(-)

diff --git a/newlib/libc/locale/newlocale.c b/newlib/libc/locale/newlocale.c
index 9193717..224b7ab 100644
--- a/newlib/libc/locale/newlocale.c
+++ b/newlib/libc/locale/newlocale.c
@@ -11,6 +11,7 @@ struct __locale_t *
 _newlocale_r (struct _reent *p, int category_mask, const char *locale,
 	      struct __locale_t *base)
 {
+  char new_categories[_LC_LAST][ENCODING_LEN + 1];
   struct __locale_t tmp_locale, *new_locale;
   int i;
 
@@ -35,61 +36,60 @@ _newlocale_r (struct _reent *p, int category_mask, const char *locale,
     return (struct __locale_t *) &__C_locale;
   /* Start with setting all values to the default locale values. */
   tmp_locale = __C_locale;
-  /* Fill out category strings. */
-  if (!*locale)
-    {
-      for (i = 1; i < _LC_LAST; ++i)
-	if (((1 << i) & category_mask) != 0)
-	  {
-	    const char *env = __get_locale_env (p, i);
-	    if (strlen (env) > ENCODING_LEN)
-	      {
-		p->_errno = EINVAL;
-		return NULL;
-	      }
-	    strcpy (tmp_locale.categories[i], env);
-	  }
-    }
-  else
+  /* Fill out new category strings. */
+  for (i = 1; i < _LC_LAST; ++i)
     {
-      for (i = 1; i < _LC_LAST; ++i)
-	if (((1 << i) & category_mask) != 0)
-	  strcpy (tmp_locale.categories[i], locale);
+      if (((1 << i) & category_mask) != 0)
+	{
+	  const char *cat = locale ?: __get_locale_env (p, i);
+	  if (strlen (cat) > ENCODING_LEN)
+	    {
+	      p->_errno = EINVAL;
+	      return NULL;
+	    }
+	  strcpy (new_categories[i], cat);
+	}
+      else
+	strcpy (new_categories[i], base ? base->categories[i] : "C");
     }
   /* Now go over all categories and set them. */
   for (i = 1; i < _LC_LAST; ++i)
     {
-      if (((1 << i) & category_mask) != 0)
+      /* If we have a base locale, and the category is not in category_mask
+	 or the new category is the base categroy, just copy over. */
+      if (base && (((1 << i) & category_mask) == 0
+		   || !strcmp (base->categories[i], new_categories[i])))
 	{
-	  /* Nothing to do for "C"/"POSIX" locale. */
-	  if (!strcmp (tmp_locale.categories[i], "C")
-	      || !strcmp (tmp_locale.categories[i], "POSIX"))
-	    continue;
-	  /* If the new locale is the old locale, just copy it over. */
-	  if (base && !strcmp (base->categories[i], tmp_locale.categories[i]))
+	  strcpy (tmp_locale.categories[i], new_categories[i]);
+	  if (i == LC_CTYPE)
 	    {
-	      if (i == LC_CTYPE)
-		{
-		  tmp_locale.wctomb = base->wctomb;
-		  tmp_locale.mbtowc = base->mbtowc;
-		  tmp_locale.cjk_lang = base->cjk_lang;
-		  tmp_locale.ctype_ptr - base->ctype_ptr;
-		}
+	      tmp_locale.wctomb = base->wctomb;
+	      tmp_locale.mbtowc = base->mbtowc;
+	      tmp_locale.cjk_lang = base->cjk_lang;
+	      tmp_locale.ctype_ptr - base->ctype_ptr;
+	    }
 #ifdef __HAVE_LOCALE_INFO__
-	      tmp_locale.lc_cat[i].ptr = base->lc_cat[i].ptr;
-	      /* Mark the value as "has still to be copied".  We do this in
-		 two steps to simplify freeing new locale types in case of a
-		 subsequent error. */
-	      tmp_locale.lc_cat[i].buf = (void *) -1;
+	  /* Mark the values as "has still to be copied".  We do this in
+	     two steps to simplify freeing new locale types in case of a
+	     subsequent error. */
+	  tmp_locale.lc_cat[i].ptr = base->lc_cat[i].ptr;
+	  tmp_locale.lc_cat[i].buf = (void *) -1;
 #else
-	      if (i == LC_CTYPE)
-		strcpy (tmp_locale.ctype_codeset, base->ctype_codeset);
-	      else if (i == LC_MESSAGES)
-		strcpy (tmp_locale.message_codeset, base->message_codeset);
+	  if (i == LC_CTYPE)
+	    strcpy (tmp_locale.ctype_codeset, base->ctype_codeset);
+	  else if (i == LC_MESSAGES)
+	    strcpy (tmp_locale.message_codeset, base->message_codeset);
 #endif
-	    }
+	}
+      /* Otherwise, if the category is in category_mask, create entry. */
+      else if (((1 << i) & category_mask) != 0)
+	{
+	  /* Nothing to do for "C"/"POSIX" locale. */
+	  if (!strcmp (new_categories[i], "C")
+	      || !strcmp (new_categories[i], "POSIX"))
+	    continue;
 	  /* Otherwise load locale data. */
-	  else if (!__loadlocale (&tmp_locale, i, tmp_locale.categories[i]))
+	  else if (!__loadlocale (&tmp_locale, i, new_categories[i]))
 	    goto error;
 	}
     }
@@ -97,17 +97,21 @@ _newlocale_r (struct _reent *p, int category_mask, const char *locale,
   new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale);
   if (!new_locale)
     goto error;
+  if (base)
+    {
 #ifdef __HAVE_LOCALE_INFO__
-  /* Second step of copying over.  At this point we can safely copy.  Make
-     sure to invalidate the copied buffer pointers in base, so a subsequent
-     freelocale (base) doesn't free the buffers now used in the new locale. */
-  for (i = 1; i < _LC_LAST; ++i)
-    if (tmp_locale.lc_cat[i].buf == (const void *) -1)
-      {
-	tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf;
-	base->lc_cat[i].buf = NULL;
-      }
+      /* Step 2 of copying over..  Make sure to invalidate the copied buffer
+	 pointers in base, so the subsequent _freelocale_r (base) doesn't free
+	 the buffers now used in the new locale. */
+      for (i = 1; i < _LC_LAST; ++i)
+	if (tmp_locale.lc_cat[i].buf == (const void *) -1)
+	  {
+	    tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf;
+	    base->lc_cat[i].ptr = base->lc_cat[i].buf = NULL;
+	  }
 #endif
+      _freelocale_r (p, base);
+    }
 
   *new_locale = tmp_locale;
   return new_locale;
@@ -117,7 +121,8 @@ error:
      Free memory and return NULL.  errno is supposed to be set already. */
 #ifdef __HAVE_LOCALE_INFO__
   for (i = 1; i < _LC_LAST; ++i)
-    if (tmp_locale.lc_cat[i].buf
+    if (((1 << i) & category_mask) != 0
+	&& tmp_locale.lc_cat[i].buf
 	&& tmp_locale.lc_cat[i].buf != (const void *) -1)
       {
 	_free_r (p, (void *) tmp_locale.lc_cat[i].ptr);


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