]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve robustness of new string-collation code.
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 27 Aug 2014 18:56:47 +0000 (11:56 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 27 Aug 2014 18:56:47 +0000 (11:56 -0700)
* configure.ac (newlocale): Check for this, not for uselocale.
* src/sysdep.c (LC_COLLATE, LC_COLLATE_MASK, freelocale, locale_t)
(newlocale, wcscoll_l): Define substitutes for platforms that
lack them, so as to simplify the mainline code.
(str_collate): Simplify the code by assuming the above definitions.
Use wcscoll_l, not uselocale, as uselocale is too fragile.  For
example, the old version left the Emacs in the wrong locale if
wcscoll reported an error.  Use 'int', not ptrdiff_t, for the int
result.  Report an error if newlocale fails.

Fixes: debbugs:18051
ChangeLog
configure.ac
src/ChangeLog
src/sysdep.c

index 9eb4637694fe634dbc8e71f825b1ec3c60994fef..a4cef305560812b58cf0c9efa5699ee5a288878e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2014-08-27  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Improve robustness of new string-collation code (Bug#18051).
+       * configure.ac (newlocale): Check for this, not for uselocale.
+
 2014-08-26  Dmitry Antipov  <dmantipov@yandex.ru>
 
        Detect features needed to handle C stack overflows.
index 4f22be4745d81e8158d50f5121c818e7ad894720..4617942409a3c3c91553ff177a16df3e5452a440 100644 (file)
@@ -3558,7 +3558,7 @@ LIBS="$LIB_PTHREAD $LIB_MATH $LIBS"
 AC_CHECK_FUNCS(accept4 fchdir gethostname \
 getrusage get_current_dir_name \
 lrand48 random rint \
-select getpagesize setlocale uselocale \
+select getpagesize setlocale newlocale \
 getrlimit setrlimit shutdown getaddrinfo \
 pthread_sigmask strsignal setitimer \
 sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
index d7066b823b969f63f62af55d7d8ab87f2c8c055c..8a32bc27b0bed9676831eeac5cef22fa90573685 100644 (file)
@@ -1,3 +1,15 @@
+2014-08-27  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Improve robustness of new string-collation code (Bug#18051).
+       * sysdep.c (LC_COLLATE, LC_COLLATE_MASK, freelocale, locale_t)
+       (newlocale, wcscoll_l): Define substitutes for platforms that
+       lack them, so as to simplify the mainline code.
+       (str_collate): Simplify the code by assuming the above definitions.
+       Use wcscoll_l, not uselocale, as uselocale is too fragile.  For
+       example, the old version left the Emacs in the wrong locale if
+       wcscoll reported an error.  Use 'int', not ptrdiff_t, for the int
+       result.  Report an error if newlocale fails.
+
 2014-08-27  Michael Albinus  <michael.albinus@gmx.de>
 
        * lisp.h (str_collate):
index 4b0f54ebe6e7ee60149bc910a73477f4534de217..d50e2398a53a1f6a7f4156e6722c26678b503510 100644 (file)
@@ -3599,24 +3599,89 @@ system_process_attributes (Lisp_Object pid)
 #ifdef __STDC_ISO_10646__
 # include <wchar.h>
 
-# if defined HAVE_USELOCALE || defined HAVE_SETLOCALE
+# if defined HAVE_NEWLOCALE || defined HAVE_SETLOCALE
 #  include <locale.h>
+# else
+#  define LC_COLLATE 0
+#  define LC_COLLATE_MASK 0
 # endif
-# ifndef HAVE_SETLOCALE
-#  define setlocale(category, locale) ((char *) 0)
+# ifndef HAVE_NEWLOCALE
+#  undef freelocale
+#  undef locale_t
+#  undef newlocale
+#  undef wcscoll_l
+#  define freelocale emacs_freelocale
+#  define locale_t emacs_locale_t
+#  define newlocale emacs_newlocale
+#  define wcscoll_l emacs_wcscoll_l
+
+typedef char const *locale_t;
+
+static locale_t
+newlocale (int category_mask, char const *locale, locale_t loc)
+{
+  return locale;
+}
+
+static void
+freelocale (locale_t loc)
+{
+}
+
+static char *
+emacs_setlocale (int category, char const *locale)
+{
+#  ifdef HAVE_SETLOCALE
+  errno = 0;
+  char *loc = setlocale (category, locale);
+  if (loc || errno)
+    return loc;
+  errno = EINVAL;
+#  else
+  errno = ENOTSUP;
+#  endif
+  return 0;
+}
+
+static int
+wcscoll_l (wchar_t const *a, wchar_t const *b, locale_t loc)
+{
+  int result = 0;
+  char *oldloc = emacs_setlocale (LC_COLLATE, NULL);
+  int err;
+
+  if (! oldloc)
+    err = errno;
+  else
+    {
+      USE_SAFE_ALLOCA;
+      char *oldcopy = SAFE_ALLOCA (strlen (oldloc) + 1);
+      strcpy (oldcopy, oldloc);
+      if (! emacs_setlocale (LC_COLLATE, loc))
+       err = errno;
+      else
+       {
+         errno = 0;
+         result = wcscoll (a, b);
+         err = errno;
+         if (! emacs_setlocale (LC_COLLATE, oldcopy))
+           err = errno;
+       }
+      SAFE_FREE ();
+    }
+
+  errno = err;
+  return result;
+}
 # endif
 
 int
 str_collate (Lisp_Object s1, Lisp_Object s2)
 {
-  ptrdiff_t res, len, i, i_byte;
+  int res, err;
+  ptrdiff_t len, i, i_byte;
   wchar_t *p1, *p2;
   Lisp_Object lc_collate;
-# ifdef HAVE_USELOCALE
-  locale_t loc = 0, oldloc = 0;
-# else
-  char *oldloc = NULL;
-# endif
 
   USE_SAFE_ALLOCA;
 
@@ -3633,44 +3698,28 @@ str_collate (Lisp_Object s1, Lisp_Object s2)
     FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte);
   *(p2+len) = 0;
 
-  /* Create a new locale object, and set it.  */
   lc_collate =
     Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment);
 
   if (STRINGP (lc_collate))
     {
-#ifdef HAVE_USELOCALE
-      loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0);
-      if (loc)
-       oldloc = uselocale (loc);
-#else
-      oldloc = setlocale (LC_COLLATE, NULL);
-      if (oldloc)
-       {
-         oldloc = xstrdup (oldloc);
-         setlocale (LC_COLLATE, SSDATA (lc_collate));
-       }
-#endif
+      locale_t loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0);
+      if (!loc)
+       error ("Wrong locale: %s", strerror (errno));
+      errno = 0;
+      res = wcscoll_l (p1, p2, loc);
+      err = errno;
+      freelocale (loc);
     }
+  else
+    {
+      errno = 0;
+      res = wcscoll (p1, p2);
+      err = errno;
+    }
+  if (err)
+    error ("Wrong argument: %s", strerror (err));
 
-  errno = 0;
-  res = wcscoll (p1, p2);
-  if (errno)
-    error ("Wrong argument: %s", strerror (errno));
-
-#ifdef HAVE_USELOCALE
-  /* Free the locale object, and reset.  */
-  if (loc)
-    freelocale (loc);
-  if (oldloc)
-    uselocale (oldloc);
-#else
-  /* Restore the original locale. */
-  setlocale (LC_COLLATE, oldloc);
-  xfree (oldloc);
-#endif
-
-  /* Return result.  */
   SAFE_FREE ();
   return res;
 }