diff options
| author | Paul Eggert | 2014-08-27 11:56:47 -0700 |
|---|---|---|
| committer | Paul Eggert | 2014-08-27 11:56:47 -0700 |
| commit | 110d87a1cc6a47e31ad9d70cc6366dd81d213860 (patch) | |
| tree | d6b77b26ec0ce70df4684c0a859989ff426e3ef5 /src | |
| parent | 17d94f1ba4333a0d53558af02583dbf80e9157ff (diff) | |
| download | emacs-110d87a1cc6a47e31ad9d70cc6366dd81d213860.tar.gz emacs-110d87a1cc6a47e31ad9d70cc6366dd81d213860.zip | |
Improve robustness of new string-collation code.
* 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
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 12 | ||||
| -rw-r--r-- | src/sysdep.c | 129 |
2 files changed, 101 insertions, 40 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d7066b823b9..8a32bc27b0b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,15 @@ | |||
| 1 | 2014-08-27 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Improve robustness of new string-collation code (Bug#18051). | ||
| 4 | * sysdep.c (LC_COLLATE, LC_COLLATE_MASK, freelocale, locale_t) | ||
| 5 | (newlocale, wcscoll_l): Define substitutes for platforms that | ||
| 6 | lack them, so as to simplify the mainline code. | ||
| 7 | (str_collate): Simplify the code by assuming the above definitions. | ||
| 8 | Use wcscoll_l, not uselocale, as uselocale is too fragile. For | ||
| 9 | example, the old version left the Emacs in the wrong locale if | ||
| 10 | wcscoll reported an error. Use 'int', not ptrdiff_t, for the int | ||
| 11 | result. Report an error if newlocale fails. | ||
| 12 | |||
| 1 | 2014-08-27 Michael Albinus <michael.albinus@gmx.de> | 13 | 2014-08-27 Michael Albinus <michael.albinus@gmx.de> |
| 2 | 14 | ||
| 3 | * lisp.h (str_collate): | 15 | * lisp.h (str_collate): |
diff --git a/src/sysdep.c b/src/sysdep.c index 4b0f54ebe6e..d50e2398a53 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -3599,24 +3599,89 @@ system_process_attributes (Lisp_Object pid) | |||
| 3599 | #ifdef __STDC_ISO_10646__ | 3599 | #ifdef __STDC_ISO_10646__ |
| 3600 | # include <wchar.h> | 3600 | # include <wchar.h> |
| 3601 | 3601 | ||
| 3602 | # if defined HAVE_USELOCALE || defined HAVE_SETLOCALE | 3602 | # if defined HAVE_NEWLOCALE || defined HAVE_SETLOCALE |
| 3603 | # include <locale.h> | 3603 | # include <locale.h> |
| 3604 | # else | ||
| 3605 | # define LC_COLLATE 0 | ||
| 3606 | # define LC_COLLATE_MASK 0 | ||
| 3604 | # endif | 3607 | # endif |
| 3605 | # ifndef HAVE_SETLOCALE | 3608 | # ifndef HAVE_NEWLOCALE |
| 3606 | # define setlocale(category, locale) ((char *) 0) | 3609 | # undef freelocale |
| 3610 | # undef locale_t | ||
| 3611 | # undef newlocale | ||
| 3612 | # undef wcscoll_l | ||
| 3613 | # define freelocale emacs_freelocale | ||
| 3614 | # define locale_t emacs_locale_t | ||
| 3615 | # define newlocale emacs_newlocale | ||
| 3616 | # define wcscoll_l emacs_wcscoll_l | ||
| 3617 | |||
| 3618 | typedef char const *locale_t; | ||
| 3619 | |||
| 3620 | static locale_t | ||
| 3621 | newlocale (int category_mask, char const *locale, locale_t loc) | ||
| 3622 | { | ||
| 3623 | return locale; | ||
| 3624 | } | ||
| 3625 | |||
| 3626 | static void | ||
| 3627 | freelocale (locale_t loc) | ||
| 3628 | { | ||
| 3629 | } | ||
| 3630 | |||
| 3631 | static char * | ||
| 3632 | emacs_setlocale (int category, char const *locale) | ||
| 3633 | { | ||
| 3634 | # ifdef HAVE_SETLOCALE | ||
| 3635 | errno = 0; | ||
| 3636 | char *loc = setlocale (category, locale); | ||
| 3637 | if (loc || errno) | ||
| 3638 | return loc; | ||
| 3639 | errno = EINVAL; | ||
| 3640 | # else | ||
| 3641 | errno = ENOTSUP; | ||
| 3642 | # endif | ||
| 3643 | return 0; | ||
| 3644 | } | ||
| 3645 | |||
| 3646 | static int | ||
| 3647 | wcscoll_l (wchar_t const *a, wchar_t const *b, locale_t loc) | ||
| 3648 | { | ||
| 3649 | int result = 0; | ||
| 3650 | char *oldloc = emacs_setlocale (LC_COLLATE, NULL); | ||
| 3651 | int err; | ||
| 3652 | |||
| 3653 | if (! oldloc) | ||
| 3654 | err = errno; | ||
| 3655 | else | ||
| 3656 | { | ||
| 3657 | USE_SAFE_ALLOCA; | ||
| 3658 | char *oldcopy = SAFE_ALLOCA (strlen (oldloc) + 1); | ||
| 3659 | strcpy (oldcopy, oldloc); | ||
| 3660 | if (! emacs_setlocale (LC_COLLATE, loc)) | ||
| 3661 | err = errno; | ||
| 3662 | else | ||
| 3663 | { | ||
| 3664 | errno = 0; | ||
| 3665 | result = wcscoll (a, b); | ||
| 3666 | err = errno; | ||
| 3667 | if (! emacs_setlocale (LC_COLLATE, oldcopy)) | ||
| 3668 | err = errno; | ||
| 3669 | } | ||
| 3670 | SAFE_FREE (); | ||
| 3671 | } | ||
| 3672 | |||
| 3673 | errno = err; | ||
| 3674 | return result; | ||
| 3675 | } | ||
| 3607 | # endif | 3676 | # endif |
| 3608 | 3677 | ||
| 3609 | int | 3678 | int |
| 3610 | str_collate (Lisp_Object s1, Lisp_Object s2) | 3679 | str_collate (Lisp_Object s1, Lisp_Object s2) |
| 3611 | { | 3680 | { |
| 3612 | ptrdiff_t res, len, i, i_byte; | 3681 | int res, err; |
| 3682 | ptrdiff_t len, i, i_byte; | ||
| 3613 | wchar_t *p1, *p2; | 3683 | wchar_t *p1, *p2; |
| 3614 | Lisp_Object lc_collate; | 3684 | Lisp_Object lc_collate; |
| 3615 | # ifdef HAVE_USELOCALE | ||
| 3616 | locale_t loc = 0, oldloc = 0; | ||
| 3617 | # else | ||
| 3618 | char *oldloc = NULL; | ||
| 3619 | # endif | ||
| 3620 | 3685 | ||
| 3621 | USE_SAFE_ALLOCA; | 3686 | USE_SAFE_ALLOCA; |
| 3622 | 3687 | ||
| @@ -3633,44 +3698,28 @@ str_collate (Lisp_Object s1, Lisp_Object s2) | |||
| 3633 | FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte); | 3698 | FETCH_STRING_CHAR_ADVANCE (*(p2+i-1), s2, i, i_byte); |
| 3634 | *(p2+len) = 0; | 3699 | *(p2+len) = 0; |
| 3635 | 3700 | ||
| 3636 | /* Create a new locale object, and set it. */ | ||
| 3637 | lc_collate = | 3701 | lc_collate = |
| 3638 | Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment); | 3702 | Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment); |
| 3639 | 3703 | ||
| 3640 | if (STRINGP (lc_collate)) | 3704 | if (STRINGP (lc_collate)) |
| 3641 | { | 3705 | { |
| 3642 | #ifdef HAVE_USELOCALE | 3706 | locale_t loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0); |
| 3643 | loc = newlocale (LC_COLLATE_MASK, SSDATA (lc_collate), 0); | 3707 | if (!loc) |
| 3644 | if (loc) | 3708 | error ("Wrong locale: %s", strerror (errno)); |
| 3645 | oldloc = uselocale (loc); | 3709 | errno = 0; |
| 3646 | #else | 3710 | res = wcscoll_l (p1, p2, loc); |
| 3647 | oldloc = setlocale (LC_COLLATE, NULL); | 3711 | err = errno; |
| 3648 | if (oldloc) | 3712 | freelocale (loc); |
| 3649 | { | ||
| 3650 | oldloc = xstrdup (oldloc); | ||
| 3651 | setlocale (LC_COLLATE, SSDATA (lc_collate)); | ||
| 3652 | } | ||
| 3653 | #endif | ||
| 3654 | } | 3713 | } |
| 3714 | else | ||
| 3715 | { | ||
| 3716 | errno = 0; | ||
| 3717 | res = wcscoll (p1, p2); | ||
| 3718 | err = errno; | ||
| 3719 | } | ||
| 3720 | if (err) | ||
| 3721 | error ("Wrong argument: %s", strerror (err)); | ||
| 3655 | 3722 | ||
| 3656 | errno = 0; | ||
| 3657 | res = wcscoll (p1, p2); | ||
| 3658 | if (errno) | ||
| 3659 | error ("Wrong argument: %s", strerror (errno)); | ||
| 3660 | |||
| 3661 | #ifdef HAVE_USELOCALE | ||
| 3662 | /* Free the locale object, and reset. */ | ||
| 3663 | if (loc) | ||
| 3664 | freelocale (loc); | ||
| 3665 | if (oldloc) | ||
| 3666 | uselocale (oldloc); | ||
| 3667 | #else | ||
| 3668 | /* Restore the original locale. */ | ||
| 3669 | setlocale (LC_COLLATE, oldloc); | ||
| 3670 | xfree (oldloc); | ||
| 3671 | #endif | ||
| 3672 | |||
| 3673 | /* Return result. */ | ||
| 3674 | SAFE_FREE (); | 3723 | SAFE_FREE (); |
| 3675 | return res; | 3724 | return res; |
| 3676 | } | 3725 | } |