xlocale: Fix potential segfault
authorJohn Marino <draco@marino.st>
Sat, 11 Jul 2015 09:52:54 +0000 (11:52 +0200)
committerJohn Marino <draco@marino.st>
Sat, 11 Jul 2015 13:09:29 +0000 (15:09 +0200)
It was possible for locale and rune locale to become out of sync causing
mb* and similar functions to be called with the wrong data, including
with a null pointer.  Unfortunately, this still does not solve the
gfortran testsuite failure related to newlocale usage.

Taken-from: FreeBSD SVN 264038 (2 APR 2014)

lib/libc/locale/setrunelocale.c
lib/libc/locale/xlocale.c

index 726f842..4e0f8ca 100644 (file)
@@ -34,7 +34,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/lib/libc/locale/setrunelocale.c 244126 2012-12-11 22:52:56Z jilles $
+ * $FreeBSD: head/lib/libc/locale/setrunelocale.c 264038 2014-04-02 11:10:46Z theraven $
  */
 
 
@@ -202,6 +202,8 @@ __set_thread_rune_locale(locale_t loc)
 
        if (loc == NULL) {
                _ThreadRuneLocale = &_DefaultRuneLocale;
+       } else if (loc == LC_GLOBAL_LOCALE) {
+               _ThreadRuneLocale = 0;
        } else {
                _ThreadRuneLocale = XLOCALE_CTYPE(loc)->runes;
        }
index 695e435..c24b776 100644 (file)
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/lib/libc/locale/xlocale.c 232498 2012-03-04 15:31:13Z theraven $
+ * $FreeBSD: head/lib/libc/locale/xlocale.c 264038 2014-04-02 11:10:46Z theraven $
  */
 
 #include <pthread.h>
@@ -154,23 +154,24 @@ __get_locale(void)
 static void
 set_thread_locale(locale_t loc)
 {
+       locale_t l = (loc == LC_GLOBAL_LOCALE) ? 0 : loc;
 
        _once(&once_control, init_key);
        
-       if (NULL != loc) {
-               xlocale_retain((struct xlocale_refcounted*)loc);
+       if (NULL != l) {
+               xlocale_retain((struct xlocale_refcounted*)l);
        }
        locale_t old = pthread_getspecific(locale_info_key);
-       if ((NULL != old) && (loc != old)) {
+       if ((NULL != old) && (l != old)) {
                xlocale_release((struct xlocale_refcounted*)old);
        }
        if (fake_tls) {
-               thread_local_locale = loc;
+               thread_local_locale = l;
        } else {
-               pthread_setspecific(locale_info_key, loc);
+               pthread_setspecific(locale_info_key, l);
        }
 #ifndef __NO_TLS
-       __thread_locale = loc;
+       __thread_locale = l;
        __set_thread_rune_locale(loc);
 #endif
 }
@@ -361,9 +362,6 @@ locale_t uselocale(locale_t loc)
 {
        locale_t old = get_thread_locale();
        if (NULL != loc) {
-               if (LC_GLOBAL_LOCALE == loc) {
-                       loc = NULL;
-               }
                set_thread_locale(loc);
        }
        return (old ? old : LC_GLOBAL_LOCALE);